Project import
diff --git a/iproute2/Android.mk b/iproute2/Android.mk
new file mode 100644
index 0000000..5053e7d
--- /dev/null
+++ b/iproute2/Android.mk
@@ -0,0 +1 @@
+include $(call all-subdir-makefiles)
diff --git a/iproute2/COPYING b/iproute2/COPYING
new file mode 100644
index 0000000..3912109
--- /dev/null
+++ b/iproute2/COPYING
@@ -0,0 +1,340 @@
+		    GNU GENERAL PUBLIC LICENSE
+		       Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.
+                       51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+			    Preamble
+
+  The licenses for most software are designed to take away your
+freedom to share and change it.  By contrast, the GNU General Public
+License is intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users.  This
+General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to
+using it.  (Some other Free Software Foundation software is covered by
+the GNU Library General Public License instead.)  You can apply it to
+your programs, too.
+
+  When we speak of free software, we are referring to freedom, not
+price.  Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+  To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+  For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have.  You must make sure that they, too, receive or can get the
+source code.  And you must show them these terms so they know their
+rights.
+
+  We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+  Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software.  If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+  Finally, any free program is threatened constantly by software
+patents.  We wish to avoid the danger that redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary.  To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+
+  The precise terms and conditions for copying, distribution and
+modification follow.
+
+		    GNU GENERAL PUBLIC LICENSE
+   TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+  0. This License applies to any program or other work which contains
+a notice placed by the copyright holder saying it may be distributed
+under the terms of this General Public License.  The "Program", below,
+refers to any such program or work, and a "work based on the Program"
+means either the Program or any derivative work under copyright law:
+that is to say, a work containing the Program or a portion of it,
+either verbatim or with modifications and/or translated into another
+language.  (Hereinafter, translation is included without limitation in
+the term "modification".)  Each licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope.  The act of
+running the Program is not restricted, and the output from the Program
+is covered only if its contents constitute a work based on the
+Program (independent of having been made by running the Program).
+Whether that is true depends on what the Program does.
+
+  1. You may copy and distribute verbatim copies of the Program's
+source code as you receive it, in any medium, provided that you
+conspicuously and appropriately publish on each copy an appropriate
+copyright notice and disclaimer of warranty; keep intact all the
+notices that refer to this License and to the absence of any warranty;
+and give any other recipients of the Program a copy of this License
+along with the Program.
+
+You may charge a fee for the physical act of transferring a copy, and
+you may at your option offer warranty protection in exchange for a fee.
+
+  2. You may modify your copy or copies of the Program or any portion
+of it, thus forming a work based on the Program, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+    a) You must cause the modified files to carry prominent notices
+    stating that you changed the files and the date of any change.
+
+    b) You must cause any work that you distribute or publish, that in
+    whole or in part contains or is derived from the Program or any
+    part thereof, to be licensed as a whole at no charge to all third
+    parties under the terms of this License.
+
+    c) If the modified program normally reads commands interactively
+    when run, you must cause it, when started running for such
+    interactive use in the most ordinary way, to print or display an
+    announcement including an appropriate copyright notice and a
+    notice that there is no warranty (or else, saying that you provide
+    a warranty) and that users may redistribute the program under
+    these conditions, and telling the user how to view a copy of this
+    License.  (Exception: if the Program itself is interactive but
+    does not normally print such an announcement, your work based on
+    the Program is not required to print an announcement.)
+
+These requirements apply to the modified work as a whole.  If
+identifiable sections of that work are not derived from the Program,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works.  But when you
+distribute the same sections as part of a whole which is a work based
+on the Program, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Program.
+
+In addition, mere aggregation of another work not based on the Program
+with the Program (or with a work based on the Program) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+  3. You may copy and distribute the Program (or a work based on it,
+under Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you also do one of the following:
+
+    a) Accompany it with the complete corresponding machine-readable
+    source code, which must be distributed under the terms of Sections
+    1 and 2 above on a medium customarily used for software interchange; or,
+
+    b) Accompany it with a written offer, valid for at least three
+    years, to give any third party, for a charge no more than your
+    cost of physically performing source distribution, a complete
+    machine-readable copy of the corresponding source code, to be
+    distributed under the terms of Sections 1 and 2 above on a medium
+    customarily used for software interchange; or,
+
+    c) Accompany it with the information you received as to the offer
+    to distribute corresponding source code.  (This alternative is
+    allowed only for noncommercial distribution and only if you
+    received the program in object code or executable form with such
+    an offer, in accord with Subsection b above.)
+
+The source code for a work means the preferred form of the work for
+making modifications to it.  For an executable work, complete source
+code means all the source code for all modules it contains, plus any
+associated interface definition files, plus the scripts used to
+control compilation and installation of the executable.  However, as a
+special exception, the source code distributed need not include
+anything that is normally distributed (in either source or binary
+form) with the major components (compiler, kernel, and so on) of the
+operating system on which the executable runs, unless that component
+itself accompanies the executable.
+
+If distribution of executable or object code is made by offering
+access to copy from a designated place, then offering equivalent
+access to copy the source code from the same place counts as
+distribution of the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+  4. You may not copy, modify, sublicense, or distribute the Program
+except as expressly provided under this License.  Any attempt
+otherwise to copy, modify, sublicense or distribute the Program is
+void, and will automatically terminate your rights under this License.
+However, parties who have received copies, or rights, from you under
+this License will not have their licenses terminated so long as such
+parties remain in full compliance.
+
+  5. You are not required to accept this License, since you have not
+signed it.  However, nothing else grants you permission to modify or
+distribute the Program or its derivative works.  These actions are
+prohibited by law if you do not accept this License.  Therefore, by
+modifying or distributing the Program (or any work based on the
+Program), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Program or works based on it.
+
+  6. Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the
+original licensor to copy, distribute or modify the Program subject to
+these terms and conditions.  You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+  7. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License.  If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Program at all.  For example, if a patent
+license would not permit royalty-free redistribution of the Program by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Program.
+
+If any portion of this section is held invalid or unenforceable under
+any particular circumstance, the balance of the section is intended to
+apply and the section as a whole is intended to apply in other
+circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system, which is
+implemented by public license practices.  Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+  8. If the distribution and/or use of the Program is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Program under this License
+may add an explicit geographical distribution limitation excluding
+those countries, so that distribution is permitted only in or among
+countries not thus excluded.  In such case, this License incorporates
+the limitation as if written in the body of this License.
+
+  9. The Free Software Foundation may publish revised and/or new versions
+of the General Public License from time to time.  Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+Each version is given a distinguishing version number.  If the Program
+specifies a version number of this License which applies to it and "any
+later version", you have the option of following the terms and conditions
+either of that version or of any later version published by the Free
+Software Foundation.  If the Program does not specify a version number of
+this License, you may choose any version ever published by the Free Software
+Foundation.
+
+  10. If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, write to the author
+to ask for permission.  For software which is copyrighted by the Free
+Software Foundation, write to the Free Software Foundation; we sometimes
+make exceptions for this.  Our decision will be guided by the two goals
+of preserving the free status of all derivatives of our free software and
+of promoting the sharing and reuse of software generally.
+
+			    NO WARRANTY
+
+  11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW.  EXCEPT WHEN
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.  THE ENTIRE RISK AS
+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU.  SHOULD THE
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
+REPAIR OR CORRECTION.
+
+  12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGES.
+
+		     END OF TERMS AND CONDITIONS
+
+	    How to Apply These Terms to Your New Programs
+
+  If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+  To do so, attach the following notices to the program.  It is safest
+to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+    <one line to give the program's name and a brief idea of what it does.>
+    Copyright (C) <year>  <name of author>
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+
+
+Also add information on how to contact you by electronic and paper mail.
+
+If the program is interactive, make it output a short notice like this
+when it starts in an interactive mode:
+
+    Gnomovision version 69, Copyright (C) year name of author
+    Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+    This is free software, and you are welcome to redistribute it
+    under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License.  Of course, the commands you use may
+be called something other than `show w' and `show c'; they could even be
+mouse-clicks or menu items--whatever suits your program.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the program, if
+necessary.  Here is a sample; alter the names:
+
+  Yoyodyne, Inc., hereby disclaims all copyright interest in the program
+  `Gnomovision' (which makes passes at compilers) written by James Hacker.
+
+  <signature of Ty Coon>, 1 April 1989
+  Ty Coon, President of Vice
+
+This General Public License does not permit incorporating your program into
+proprietary programs.  If your program is a subroutine library, you may
+consider it more useful to permit linking proprietary applications with the
+library.  If this is what you want to do, use the GNU Library General
+Public License instead of this License.
diff --git a/iproute2/CleanSpec.mk b/iproute2/CleanSpec.mk
new file mode 100644
index 0000000..b84e1b6
--- /dev/null
+++ b/iproute2/CleanSpec.mk
@@ -0,0 +1,49 @@
+# Copyright (C) 2007 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+# If you don't need to do a full clean build but would like to touch
+# a file or delete some intermediate files, add a clean step to the end
+# of the list.  These steps will only be run once, if they haven't been
+# run before.
+#
+# E.g.:
+#     $(call add-clean-step, touch -c external/sqlite/sqlite3.h)
+#     $(call add-clean-step, rm -rf $(PRODUCT_OUT)/obj/STATIC_LIBRARIES/libz_intermediates)
+#
+# Always use "touch -c" and "rm -f" or "rm -rf" to gracefully deal with
+# files that are missing or have been moved.
+#
+# Use $(PRODUCT_OUT) to get to the "out/target/product/blah/" directory.
+# Use $(OUT_DIR) to refer to the "out" directory.
+#
+# If you need to re-do something that's already mentioned, just copy
+# the command and add it to the bottom of the list.  E.g., if a change
+# that you made last week required touching a file and a change you
+# made today requires touching the same file, just copy the old
+# touch step and add it to the end of the list.
+#
+# ************************************************
+# NEWER CLEAN STEPS MUST BE AT THE END OF THE LIST
+# ************************************************
+
+# For example:
+#$(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/APPS/AndroidTests_intermediates)
+#$(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/JAVA_LIBRARIES/core_intermediates)
+#$(call add-clean-step, find $(OUT_DIR) -type f -name "IGTalkSession*" -print0 | xargs -0 rm -f)
+#$(call add-clean-step, rm -rf $(PRODUCT_OUT)/data/*)
+
+# ************************************************
+# NEWER CLEAN STEPS MUST BE AT THE END OF THE LIST
+# ************************************************
diff --git a/iproute2/MODULE_LICENSE_GPL b/iproute2/MODULE_LICENSE_GPL
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/iproute2/MODULE_LICENSE_GPL
diff --git a/iproute2/Makefile b/iproute2/Makefile
new file mode 100644
index 0000000..67176be
--- /dev/null
+++ b/iproute2/Makefile
@@ -0,0 +1,88 @@
+PREFIX?=/usr
+LIBDIR?=$(PREFIX)/lib
+SBINDIR?=/sbin
+CONFDIR?=/etc/iproute2
+DATADIR?=$(PREFIX)/share
+DOCDIR?=$(DATADIR)/doc/iproute2
+MANDIR?=$(DATADIR)/man
+ARPDDIR?=/var/lib/arpd
+KERNEL_INCLUDE?=/usr/include
+
+# Path to db_185.h include
+DBM_INCLUDE:=$(DESTDIR)/usr/include
+
+SHARED_LIBS = y
+
+DEFINES= -DRESOLVE_HOSTNAMES -DLIBDIR=\"$(LIBDIR)\"
+ifneq ($(SHARED_LIBS),y)
+DEFINES+= -DNO_SHARED_LIBS
+endif
+
+DEFINES+=-DCONFDIR=\"$(CONFDIR)\"
+
+#options for decnet
+ADDLIB+=dnet_ntop.o dnet_pton.o
+
+#options for ipx
+ADDLIB+=ipx_ntop.o ipx_pton.o
+
+#options for mpls
+ADDLIB+=mpls_ntop.o mpls_pton.o
+
+CC = gcc
+HOSTCC = gcc
+DEFINES += -D_GNU_SOURCE
+# Turn on transparent support for LFS
+DEFINES += -D_FILE_OFFSET_BITS=64 -D_LARGEFILE_SOURCE -D_LARGEFILE64_SOURCE
+CCOPTS = -O2
+WFLAGS := -Wall -Wstrict-prototypes  -Wmissing-prototypes
+WFLAGS += -Wmissing-declarations -Wold-style-definition -Wformat=2
+
+CFLAGS := $(WFLAGS) $(CCOPTS) -I../include $(DEFINES) $(CFLAGS)
+YACCFLAGS = -d -t -v
+
+SUBDIRS=lib ip tc bridge misc netem genl tipc man
+
+LIBNETLINK=../lib/libnetlink.a ../lib/libutil.a
+LDLIBS += $(LIBNETLINK)
+
+all: Config
+	@set -e; \
+	for i in $(SUBDIRS); \
+	do $(MAKE) $(MFLAGS) -C $$i; done
+
+Config:
+	sh configure $(KERNEL_INCLUDE)
+
+install: all
+	install -m 0755 -d $(DESTDIR)$(SBINDIR)
+	install -m 0755 -d $(DESTDIR)$(CONFDIR)
+	install -m 0755 -d $(DESTDIR)$(ARPDDIR)
+	install -m 0755 -d $(DESTDIR)$(DOCDIR)/examples
+	install -m 0755 -d $(DESTDIR)$(DOCDIR)/examples/diffserv
+	install -m 0644 README.iproute2+tc $(shell find examples -maxdepth 1 -type f) \
+		$(DESTDIR)$(DOCDIR)/examples
+	install -m 0644 $(shell find examples/diffserv -maxdepth 1 -type f) \
+		$(DESTDIR)$(DOCDIR)/examples/diffserv
+	@for i in $(SUBDIRS) doc; do $(MAKE) -C $$i install; done
+	install -m 0644 $(shell find etc/iproute2 -maxdepth 1 -type f) $(DESTDIR)$(CONFDIR)
+
+snapshot:
+	echo "static const char SNAPSHOT[] = \""`date +%y%m%d`"\";" \
+		> include/SNAPSHOT.h
+
+clean:
+	@for i in $(SUBDIRS) doc; \
+	do $(MAKE) $(MFLAGS) -C $$i clean; done
+
+clobber:
+	touch Config
+	$(MAKE) $(MFLAGS) clean
+	rm -f Config cscope.*
+
+distclean: clobber
+
+cscope:
+	cscope -b -q -R -Iinclude -sip -slib -smisc -snetem -stc
+
+.EXPORT_ALL_VARIABLES:
diff --git a/iproute2/NOTICE b/iproute2/NOTICE
new file mode 100644
index 0000000..3912109
--- /dev/null
+++ b/iproute2/NOTICE
@@ -0,0 +1,340 @@
+		    GNU GENERAL PUBLIC LICENSE
+		       Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.
+                       51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+			    Preamble
+
+  The licenses for most software are designed to take away your
+freedom to share and change it.  By contrast, the GNU General Public
+License is intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users.  This
+General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to
+using it.  (Some other Free Software Foundation software is covered by
+the GNU Library General Public License instead.)  You can apply it to
+your programs, too.
+
+  When we speak of free software, we are referring to freedom, not
+price.  Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+  To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+  For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have.  You must make sure that they, too, receive or can get the
+source code.  And you must show them these terms so they know their
+rights.
+
+  We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+  Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software.  If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+  Finally, any free program is threatened constantly by software
+patents.  We wish to avoid the danger that redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary.  To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+
+  The precise terms and conditions for copying, distribution and
+modification follow.
+
+		    GNU GENERAL PUBLIC LICENSE
+   TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+  0. This License applies to any program or other work which contains
+a notice placed by the copyright holder saying it may be distributed
+under the terms of this General Public License.  The "Program", below,
+refers to any such program or work, and a "work based on the Program"
+means either the Program or any derivative work under copyright law:
+that is to say, a work containing the Program or a portion of it,
+either verbatim or with modifications and/or translated into another
+language.  (Hereinafter, translation is included without limitation in
+the term "modification".)  Each licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope.  The act of
+running the Program is not restricted, and the output from the Program
+is covered only if its contents constitute a work based on the
+Program (independent of having been made by running the Program).
+Whether that is true depends on what the Program does.
+
+  1. You may copy and distribute verbatim copies of the Program's
+source code as you receive it, in any medium, provided that you
+conspicuously and appropriately publish on each copy an appropriate
+copyright notice and disclaimer of warranty; keep intact all the
+notices that refer to this License and to the absence of any warranty;
+and give any other recipients of the Program a copy of this License
+along with the Program.
+
+You may charge a fee for the physical act of transferring a copy, and
+you may at your option offer warranty protection in exchange for a fee.
+
+  2. You may modify your copy or copies of the Program or any portion
+of it, thus forming a work based on the Program, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+    a) You must cause the modified files to carry prominent notices
+    stating that you changed the files and the date of any change.
+
+    b) You must cause any work that you distribute or publish, that in
+    whole or in part contains or is derived from the Program or any
+    part thereof, to be licensed as a whole at no charge to all third
+    parties under the terms of this License.
+
+    c) If the modified program normally reads commands interactively
+    when run, you must cause it, when started running for such
+    interactive use in the most ordinary way, to print or display an
+    announcement including an appropriate copyright notice and a
+    notice that there is no warranty (or else, saying that you provide
+    a warranty) and that users may redistribute the program under
+    these conditions, and telling the user how to view a copy of this
+    License.  (Exception: if the Program itself is interactive but
+    does not normally print such an announcement, your work based on
+    the Program is not required to print an announcement.)
+
+These requirements apply to the modified work as a whole.  If
+identifiable sections of that work are not derived from the Program,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works.  But when you
+distribute the same sections as part of a whole which is a work based
+on the Program, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Program.
+
+In addition, mere aggregation of another work not based on the Program
+with the Program (or with a work based on the Program) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+  3. You may copy and distribute the Program (or a work based on it,
+under Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you also do one of the following:
+
+    a) Accompany it with the complete corresponding machine-readable
+    source code, which must be distributed under the terms of Sections
+    1 and 2 above on a medium customarily used for software interchange; or,
+
+    b) Accompany it with a written offer, valid for at least three
+    years, to give any third party, for a charge no more than your
+    cost of physically performing source distribution, a complete
+    machine-readable copy of the corresponding source code, to be
+    distributed under the terms of Sections 1 and 2 above on a medium
+    customarily used for software interchange; or,
+
+    c) Accompany it with the information you received as to the offer
+    to distribute corresponding source code.  (This alternative is
+    allowed only for noncommercial distribution and only if you
+    received the program in object code or executable form with such
+    an offer, in accord with Subsection b above.)
+
+The source code for a work means the preferred form of the work for
+making modifications to it.  For an executable work, complete source
+code means all the source code for all modules it contains, plus any
+associated interface definition files, plus the scripts used to
+control compilation and installation of the executable.  However, as a
+special exception, the source code distributed need not include
+anything that is normally distributed (in either source or binary
+form) with the major components (compiler, kernel, and so on) of the
+operating system on which the executable runs, unless that component
+itself accompanies the executable.
+
+If distribution of executable or object code is made by offering
+access to copy from a designated place, then offering equivalent
+access to copy the source code from the same place counts as
+distribution of the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+  4. You may not copy, modify, sublicense, or distribute the Program
+except as expressly provided under this License.  Any attempt
+otherwise to copy, modify, sublicense or distribute the Program is
+void, and will automatically terminate your rights under this License.
+However, parties who have received copies, or rights, from you under
+this License will not have their licenses terminated so long as such
+parties remain in full compliance.
+
+  5. You are not required to accept this License, since you have not
+signed it.  However, nothing else grants you permission to modify or
+distribute the Program or its derivative works.  These actions are
+prohibited by law if you do not accept this License.  Therefore, by
+modifying or distributing the Program (or any work based on the
+Program), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Program or works based on it.
+
+  6. Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the
+original licensor to copy, distribute or modify the Program subject to
+these terms and conditions.  You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+  7. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License.  If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Program at all.  For example, if a patent
+license would not permit royalty-free redistribution of the Program by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Program.
+
+If any portion of this section is held invalid or unenforceable under
+any particular circumstance, the balance of the section is intended to
+apply and the section as a whole is intended to apply in other
+circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system, which is
+implemented by public license practices.  Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+  8. If the distribution and/or use of the Program is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Program under this License
+may add an explicit geographical distribution limitation excluding
+those countries, so that distribution is permitted only in or among
+countries not thus excluded.  In such case, this License incorporates
+the limitation as if written in the body of this License.
+
+  9. The Free Software Foundation may publish revised and/or new versions
+of the General Public License from time to time.  Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+Each version is given a distinguishing version number.  If the Program
+specifies a version number of this License which applies to it and "any
+later version", you have the option of following the terms and conditions
+either of that version or of any later version published by the Free
+Software Foundation.  If the Program does not specify a version number of
+this License, you may choose any version ever published by the Free Software
+Foundation.
+
+  10. If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, write to the author
+to ask for permission.  For software which is copyrighted by the Free
+Software Foundation, write to the Free Software Foundation; we sometimes
+make exceptions for this.  Our decision will be guided by the two goals
+of preserving the free status of all derivatives of our free software and
+of promoting the sharing and reuse of software generally.
+
+			    NO WARRANTY
+
+  11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW.  EXCEPT WHEN
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.  THE ENTIRE RISK AS
+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU.  SHOULD THE
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
+REPAIR OR CORRECTION.
+
+  12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGES.
+
+		     END OF TERMS AND CONDITIONS
+
+	    How to Apply These Terms to Your New Programs
+
+  If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+  To do so, attach the following notices to the program.  It is safest
+to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+    <one line to give the program's name and a brief idea of what it does.>
+    Copyright (C) <year>  <name of author>
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+
+
+Also add information on how to contact you by electronic and paper mail.
+
+If the program is interactive, make it output a short notice like this
+when it starts in an interactive mode:
+
+    Gnomovision version 69, Copyright (C) year name of author
+    Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+    This is free software, and you are welcome to redistribute it
+    under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License.  Of course, the commands you use may
+be called something other than `show w' and `show c'; they could even be
+mouse-clicks or menu items--whatever suits your program.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the program, if
+necessary.  Here is a sample; alter the names:
+
+  Yoyodyne, Inc., hereby disclaims all copyright interest in the program
+  `Gnomovision' (which makes passes at compilers) written by James Hacker.
+
+  <signature of Ty Coon>, 1 April 1989
+  Ty Coon, President of Vice
+
+This General Public License does not permit incorporating your program into
+proprietary programs.  If your program is a subroutine library, you may
+consider it more useful to permit linking proprietary applications with the
+library.  If this is what you want to do, use the GNU Library General
+Public License instead of this License.
diff --git a/iproute2/README b/iproute2/README
new file mode 100644
index 0000000..c7a5118
--- /dev/null
+++ b/iproute2/README
@@ -0,0 +1,43 @@
+This is a set of utilities for Linux networking.
+
+Information:
+    http://www.linuxfoundation.org/collaborate/workgroups/networking/iproute2
+
+Download:
+    http://www.kernel.org/pub/linux/utils/net/iproute2/
+
+Repository:
+    git://git.kernel.org/pub/scm/linux/kernel/git/shemminger/iproute2.git
+
+How to compile this.
+--------------------
+1. libdbm
+
+arpd needs to have the db4 development libraries. For Debian
+users this is the package with a name like libdb4.x-dev.
+DBM_INCLUDE points to the directory with db_185.h which
+is the include file used by arpd to get to the old format Berkeley
+database routines.  Often this is in the db-devel package.
+
+2. make
+
+The makefile will automatically build a Config file which
+contains whether or not ATM is available, etc.
+
+3. To make documentation, cd to doc/ directory , then
+   look at start of Makefile and set correct values for
+   PAGESIZE=a4		, ie: a4 , letter ...	(string)
+   PAGESPERPAGE=2	, ie: 1 , 2 ...		(numeric)
+   and make there. It assumes, that latex, dvips and psnup
+   are in your path.
+
+4. This package includes matching sanitized kernel headers because
+   the build environment may not have up to date versions. See Makefile
+   if you have special requirements and need to point at different
+   kernel include files.
+
+Stephen Hemminger
+stephen@networkplumber.org
+
+Alexey Kuznetsov
+kuznet@ms2.inr.ac.ru
diff --git a/iproute2/README.decnet b/iproute2/README.decnet
new file mode 100644
index 0000000..4300f90
--- /dev/null
+++ b/iproute2/README.decnet
@@ -0,0 +1,33 @@
+
+Here are a few quick points about DECnet support...
+
+ o iproute2 is the tool of choice for configuring the DECnet support for
+   Linux. For many features, it is the only tool which can be used to
+   configure them.
+
+ o No name resolution is available as yet, all addresses must be
+   entered numerically.
+
+ o Remember to set the hardware address of the interface using: 
+
+   ip link set ethX address xx:xx:xx:xx:xx:xx
+      (where xx:xx:xx:xx:xx:xx is the MAC address for your DECnet node
+       address)
+
+   if your Ethernet card won't listen to more than one unicast
+   mac address at once. If the Linux DECnet stack doesn't talk to
+   any other DECnet nodes, then check this with tcpdump and if its
+   a problem, change the mac address (but do this _before_ starting
+   any other network protocol on the interface)
+
+ o Whilst you can use ip addr add to add more than one DECnet address to an
+   interface, don't expect addresses which are not the same as the
+   kernels node address to work properly with 2.4 kernels. This should
+   be fine with 2.6 kernels as the routing code has been extensively
+   modified and improved.
+
+ o The DECnet support is currently self contained. It does not depend on
+   the libdnet library.
+
+Steve Whitehouse <steve@chygwyn.com>
+
diff --git a/iproute2/README.devel b/iproute2/README.devel
new file mode 100644
index 0000000..9b7d11e
--- /dev/null
+++ b/iproute2/README.devel
@@ -0,0 +1,15 @@
+Iproute2 development is closely tied to Linux kernel networking
+development. Most new features require a kernel and a utility component.
+
+Please submit both to the Linux networking mailing list
+   <netdev@vger.kernel.org>
+
+The current source is in the git repository:
+    git://git.kernel.org/pub/scm/linux/kernel/git/shemminger/iproute2.git
+
+The master branch contains the source corresponding to the current
+code in the mainline Linux kernel (ie follows Linus). The net-next
+branch is a temporary branch that tracks the code intended for the
+next release; it corresponds with networking development branch in
+the kernel.
+
diff --git a/iproute2/README.distribution b/iproute2/README.distribution
new file mode 100644
index 0000000..4e2e8ea
--- /dev/null
+++ b/iproute2/README.distribution
@@ -0,0 +1,95 @@
+I. About the distribution tables
+
+The table used for "synthesizing" the distribution is essentially a scaled,
+translated, inverse to the cumulative distribution function.
+
+Here's how to think about it: Let F() be the cumulative distribution
+function for a probability distribution X.  We'll assume we've scaled
+things so that X has mean 0 and standard deviation 1, though that's not
+so important here.  Then:
+
+	F(x) = P(X <= x) = \int_{-inf}^x f
+
+where f is the probability density function.
+
+F is monotonically increasing, so has an inverse function G, with range
+0 to 1.  Here, G(t) = the x such that P(X <= x) = t.  (In general, G may
+have singularities if X has point masses, i.e., points x such that
+P(X = x) > 0.)
+
+Now we create a tabular representation of G as follows:  Choose some table
+size N, and for the ith entry, put in G(i/N).  Let's call this table T.
+
+The claim now is, I can create a (discrete) random variable Y whose
+distribution has the same approximate "shape" as X, simply by letting
+Y = T(U), where U is a discrete uniform random variable with range 1 to N.
+To see this, it's enough to show that Y's cumulative distribution function,
+(let's call it H), is a discrete approximation to F.  But
+
+	H(x) = P(Y <= x)
+	     = (# of entries in T <= x) / N   -- as Y chosen uniformly from T
+	     = i/N, where i is the largest integer such that G(i/N) <= x
+	     = i/N, where i is the largest integer such that i/N <= F(x)
+	     		-- since G and F are inverse functions (and F is
+	     		   increasing)
+	     = floor(N*F(x))/N
+
+as desired.
+
+II. How to create distribution tables (in theory)
+
+How can we create this table in practice? In some cases, F may have a
+simple expression which allows evaluating its inverse directly.  The
+Pareto distribution is one example of this.  In other cases, and
+especially for matching an experimentally observed distribution, it's
+easiest simply to create a table for F and "invert" it.  Here, we give
+a concrete example, namely how the new "experimental" distribution was
+created.
+
+1. Collect enough data points to characterize the distribution.  Here, I
+collected 25,000 "ping" roundtrip times to a "distant" point (time.nist.gov).
+That's far more data than is really necessary, but it was fairly painless to
+collect it, so...
+
+2. Normalize the data so that it has mean 0 and standard deviation 1.
+
+3. Determine the cumulative distribution.  The code I wrote creates a table
+covering the range -10 to +10, with granularity .00005.  Obviously, this
+is absurdly over-precise, but since it's a one-time only computation, I
+figured it hardly mattered.
+
+4. Invert the table: for each table entry F(x) = y, make the y*TABLESIZE
+(here, 4096) entry be x*TABLEFACTOR (here, 8192).  This creates a table
+for the ("normalized") inverse of size TABLESIZE, covering its domain 0
+to 1 with granularity 1/TABLESIZE.  Note that even with the granularity
+used in creating the table for F, it's possible not all the entries in
+the table for G will be filled in.  So, make a pass through the
+inverse's table, filling in any missing entries by linear interpolation.
+
+III. How to create distribution tables (in practice)
+
+If you want to do all this yourself, I've provided several tools to help:
+
+1. maketable does the steps 2-4 above, and then generates the appropriate
+header file.  So if you have your own time distribution, you can generate
+the header simply by:
+
+	maketable < time.values > header.h
+
+2. As explained in the other README file, the somewhat sleazy way I have
+of generating correlated values needs correction.  You can generate your
+own correction tables by compiling makesigtable and makemutable with
+your header file.  Check the Makefile to see how this is done.
+
+3. Warning: maketable, makesigtable and especially makemutable do
+enormous amounts of floating point arithmetic.  Don't try running
+these on an old 486.  (NIST Net itself will run fine on such a
+system, since in operation, it just needs to do a few simple integral
+calculations.  But getting there takes some work.)
+
+4. The tables produced are all normalized for mean 0 and standard
+deviation 1.  How do you know what values to use for real?  Here, I've
+provided a simple "stats" utility.  Give it a series of floating point
+values, and it will return their mean (mu), standard deviation (sigma),
+and correlation coefficient (rho).  You can then plug these values
+directly into NIST Net.
diff --git a/iproute2/README.iproute2+tc b/iproute2/README.iproute2+tc
new file mode 100644
index 0000000..2a5638d
--- /dev/null
+++ b/iproute2/README.iproute2+tc
@@ -0,0 +1,123 @@
+iproute2+tc*
+
+It's the first release of Linux traffic control engine.
+
+
+NOTES.
+* csz scheduler is inoperational at the moment, and probably
+  never will be repaired but replaced with h-pfq scheduler.
+* To use "fw" classifier you will need ipfwchains patch.
+* No manual available. Ask me, if you have problems (only try to guess
+  answer yourself at first 8)).
+
+
+Micro-manual how to start it the first time
+-------------------------------------------
+
+A. Attach CBQ to eth1:
+
+tc qdisc add dev eth1 root handle 1: cbq bandwidth 10Mbit allot 1514 cell 8 \
+avpkt 1000 mpu 64
+
+B. Add root class:
+
+tc class add dev eth1 parent 1:0 classid 1:1 cbq bandwidth 10Mbit rate 10Mbit \
+allot 1514 cell 8 weight 1Mbit prio 8 maxburst 20 avpkt 1000
+
+C. Add default interactive class:
+
+tc class add dev eth1 parent 1:1 classid 1:2 cbq bandwidth 10Mbit rate 1Mbit \
+allot 1514 cell 8 weight 100Kbit prio 3 maxburst 20 avpkt 1000 split 1:0 \
+defmap c0
+
+D. Add default class:
+
+tc class add dev eth1 parent 1:1 classid 1:3 cbq bandwidth 10Mbit rate 8Mbit \
+allot 1514 cell 8 weight 800Kbit prio 7 maxburst 20 avpkt 1000 split 1:0 \
+defmap 3f
+
+etc. etc. etc. Well, it is enough to start 8) The rest can be guessed 8)
+Look also at more elaborated example, ready to start rsvpd,
+in rsvp/cbqinit.eth1.
+
+
+Terminology and advices about setting CBQ parameters may be found in Sally Floyd
+papers. 
+
+
+Pairs X:Y are class handles, X:0 are qdisc handles.
+weight should be proportional to rate for leaf classes
+(I choosed it ten times less, but it is not necessary)
+
+defmap is bitmap of logical priorities served by this class.
+
+E. Another qdiscs are simpler. F.e. let's join TBF on class 1:2
+
+tc qdisc add dev eth1 parent 1:2 tbf rate 64Kbit buffer 5Kb/8 limit 10Kb
+
+F. Look at all that we created:
+
+tc qdisc ls dev eth1
+tc class ls dev eth1
+
+G. Install "route" classifier on root of cbq and map destination from realm
+1 to class 1:2
+
+tc filter add dev eth1 parent 1:0 protocol ip prio 100 route to 1 classid 1:2
+
+H. Assign routes to 10.11.12.0/24 to realm 1
+
+ip route add 10.11.12.0/24 dev eth1 via whatever realm 1
+
+etc. The same thing can be made with rules.
+I still did not test ipchains, but they should work too.
+
+
+Setup and code example of BPF classifier and action can be found under
+examples/bpf/, which should explain everything for getting started.
+
+
+Setup of rsvp and u32 classifiers is more hairy.
+If you read RSVP specs, you will understand how rsvp classifier
+works easily. What's about u32... That's example:
+
+
+#! /bin/sh
+
+TC=/home/root/tc
+
+# Setup classifier root on eth1 root (it is cbq)
+$TC filter add dev eth1 parent 1:0 prio 5 protocol ip u32
+
+# Create hash table of 256 slots with ID 1:
+$TC filter add dev eth1 parent 1:0 prio 5 handle 1: u32 divisor 256
+
+# Add to 6th slot of hash table rule to select tcp/telnet to 193.233.7.75
+# direct it to class 1:4 and prescribe to fall to best effort,
+# if traffic violate TBF (32kbit,5K)
+$TC filter add dev eth1 parent 1:0 prio 5 u32 ht 1:6: \
+	match ip dst 193.233.7.75 \
+	match tcp dst 0x17 0xffff \
+	flowid 1:4 \
+	police rate 32kbit buffer 5kb/8 mpu 64 mtu 1514 index 1
+
+# Add to 1th slot of hash table rule to select icmp to 193.233.7.75
+# direct it to class 1:4 and prescribe to fall to best effort,
+# if traffic violate TBF (10kbit,5K)
+$TC filter add dev eth1 parent 1:0 prio 5 u32 ht 1:: \
+	sample ip protocol 1 0xff \
+	match ip dst 193.233.7.75 \
+	flowid 1:4 \
+	police rate 10kbit buffer 5kb/8 mpu 64 mtu 1514 index 2
+
+# Lookup hash table, if it is not fragmented frame
+# Use protocol as hash key
+$TC filter add dev eth1 parent 1:0 prio 5 handle ::1 u32 ht 800:: \
+	match ip nofrag \
+	offset mask 0x0F00 shift 6 \
+	hashkey mask 0x00ff0000 at 8 \
+	link 1:
+
+
+Alexey Kuznetsov
+kuznet@ms2.inr.ac.ru
diff --git a/iproute2/README.lnstat b/iproute2/README.lnstat
new file mode 100644
index 0000000..057925f
--- /dev/null
+++ b/iproute2/README.lnstat
@@ -0,0 +1,81 @@
+lnstat - linux networking statistics
+(C) 2004 Harald Welte <laforge@gnumonks.org
+======================================================================
+
+This tool is a generalized and more feature-complete replacement for the old
+'rtstat' program.
+
+In addition to routing cache statistics, it supports any kind of statistics
+the linux kernel exports via a file in /proc/net/stat.  In a stock 2.6.9
+kernel, this is 
+	per-protocol neighbour cache statistics 
+		(ipv4, ipv6, atm, decnet)
+	routing cache statistics
+		(ipv4)
+	connection tracking statistics
+		(ipv4)
+
+Please note that lnstat will adopt to any additional statistics that might be
+added to the kernel at some later point
+
+I personally always like examples more than any reference documentation, so I
+list the following examples.  If somebody wants to do a manpage, feel free
+to send me a patch :)
+
+EXAMPLES:
+
+In order to get a list of supported statistics files, you can run
+
+	lnstat -d
+
+It will display something like
+ 
+/proc/net/stat/arp_cache:
+         1: entries
+         2: allocs
+         3: destroys
+[...]
+/proc/net/stat/rt_cache:
+         1: entries
+         2: in_hit
+         3: in_slow_tot
+
+You can now select the files/keys you are interested by something like
+
+	lnstat -k arp_cache:entries,rt_cache:in_hit,arp_cache:destroys
+
+arp_cach|rt_cache|arp_cach|
+ entries|  in_hit|destroys|
+       6|       6|       0|
+       6|       0|       0|
+       6|       2|       0|
+
+
+You can specify the interval (e.g. 10 seconds) by:
+	
+	lnstat -i 10
+
+You can specify to only use one particular statistics file:
+
+	lnstat -f ip_conntrack
+
+You can specify individual field widths 
+
+	lnstat -k arp_cache:entries,rt_cache:entries -w 20,8
+
+You can specify not to print a header at all
+	
+	lnstat -s 0
+
+You can specify to print a header only at start of the program
+
+	lnstat -s 1
+
+You can specify to print a header at start and every 20 lines:
+
+	lnstat -s 20
+
+You can specify the number of samples you want to take (e.g. 5):
+	
+	lnstat -c 5
+
diff --git a/iproute2/bridge/Makefile b/iproute2/bridge/Makefile
new file mode 100644
index 0000000..9800753
--- /dev/null
+++ b/iproute2/bridge/Makefile
@@ -0,0 +1,18 @@
+BROBJ = bridge.o fdb.o monitor.o link.o mdb.o vlan.o
+
+include ../Config
+
+ifeq ($(IP_CONFIG_SETNS),y)
+	CFLAGS += -DHAVE_SETNS
+endif
+
+all: bridge
+
+bridge: $(BROBJ) $(LIBNETLINK) 
+
+install: all
+	install -m 0755 bridge $(DESTDIR)$(SBINDIR)
+
+clean:
+	rm -f $(BROBJ) bridge
+
diff --git a/iproute2/bridge/br_common.h b/iproute2/bridge/br_common.h
new file mode 100644
index 0000000..169a162
--- /dev/null
+++ b/iproute2/bridge/br_common.h
@@ -0,0 +1,20 @@
+extern int print_linkinfo(const struct sockaddr_nl *who,
+			  struct nlmsghdr *n,
+			  void *arg);
+extern int print_fdb(const struct sockaddr_nl *who,
+		     struct nlmsghdr *n, void *arg);
+extern int print_mdb(const struct sockaddr_nl *who,
+		     struct nlmsghdr *n, void *arg);
+
+extern int do_fdb(int argc, char **argv);
+extern int do_mdb(int argc, char **argv);
+extern int do_monitor(int argc, char **argv);
+extern int do_vlan(int argc, char **argv);
+extern int do_link(int argc, char **argv);
+
+extern int preferred_family;
+extern int show_stats;
+extern int show_details;
+extern int timestamp;
+extern int compress_vlans;
+extern struct rtnl_handle rth;
diff --git a/iproute2/bridge/bridge.c b/iproute2/bridge/bridge.c
new file mode 100644
index 0000000..72f153f
--- /dev/null
+++ b/iproute2/bridge/bridge.c
@@ -0,0 +1,204 @@
+/*
+ * Get/set/delete bridge with netlink
+ *
+ * Authors:	Stephen Hemminger <shemminger@vyatta.com>
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <sys/socket.h>
+#include <string.h>
+#include <errno.h>
+
+#include "SNAPSHOT.h"
+#include "utils.h"
+#include "br_common.h"
+#include "namespace.h"
+
+struct rtnl_handle rth = { .fd = -1 };
+int preferred_family = AF_UNSPEC;
+int resolve_hosts;
+int oneline;
+int show_stats;
+int show_details;
+int compress_vlans;
+int timestamp;
+char *batch_file;
+int force;
+const char *_SL_;
+
+static void usage(void) __attribute__((noreturn));
+
+static void usage(void)
+{
+	fprintf(stderr,
+"Usage: bridge [ OPTIONS ] OBJECT { COMMAND | help }\n"
+"       bridge [ -force ] -batch filename\n"
+"where	OBJECT := { link | fdb | mdb | vlan | monitor }\n"
+"	OPTIONS := { -V[ersion] | -s[tatistics] | -d[etails] |\n"
+"		     -o[neline] | -t[imestamp] | -n[etns] name |\n"
+"		     -c[ompressvlans] }\n");
+	exit(-1);
+}
+
+static int do_help(int argc, char **argv)
+{
+	usage();
+}
+
+
+static const struct cmd {
+	const char *cmd;
+	int (*func)(int argc, char **argv);
+} cmds[] = {
+	{ "link",	do_link },
+	{ "fdb",	do_fdb },
+	{ "mdb",	do_mdb },
+	{ "vlan",	do_vlan },
+	{ "monitor",	do_monitor },
+	{ "help",	do_help },
+	{ 0 }
+};
+
+static int do_cmd(const char *argv0, int argc, char **argv)
+{
+	const struct cmd *c;
+
+	for (c = cmds; c->cmd; ++c) {
+		if (matches(argv0, c->cmd) == 0)
+			return c->func(argc-1, argv+1);
+	}
+
+	fprintf(stderr,
+		"Object \"%s\" is unknown, try \"bridge help\".\n", argv0);
+	return -1;
+}
+
+static int batch(const char *name)
+{
+	char *line = NULL;
+	size_t len = 0;
+	int ret = EXIT_SUCCESS;
+
+	if (name && strcmp(name, "-") != 0) {
+		if (freopen(name, "r", stdin) == NULL) {
+			fprintf(stderr,
+				"Cannot open file \"%s\" for reading: %s\n",
+				name, strerror(errno));
+			return EXIT_FAILURE;
+		}
+	}
+
+	if (rtnl_open(&rth, 0) < 0) {
+		fprintf(stderr, "Cannot open rtnetlink\n");
+		return EXIT_FAILURE;
+	}
+
+	cmdlineno = 0;
+	while (getcmdline(&line, &len, stdin) != -1) {
+		char *largv[100];
+		int largc;
+
+		largc = makeargs(line, largv, 100);
+		if (largc == 0)
+			continue;       /* blank line */
+
+		if (do_cmd(largv[0], largc, largv)) {
+			fprintf(stderr, "Command failed %s:%d\n",
+				name, cmdlineno);
+			ret = EXIT_FAILURE;
+			if (!force)
+				break;
+		}
+	}
+	if (line)
+		free(line);
+
+	rtnl_close(&rth);
+	return ret;
+}
+
+int
+main(int argc, char **argv)
+{
+	while (argc > 1) {
+		const char *opt = argv[1];
+
+		if (strcmp(opt, "--") == 0) {
+			argc--; argv++;
+			break;
+		}
+		if (opt[0] != '-')
+			break;
+		if (opt[1] == '-')
+			opt++;
+
+		if (matches(opt, "-help") == 0) {
+			usage();
+		} else if (matches(opt, "-Version") == 0) {
+			printf("bridge utility, 0.0\n");
+			exit(0);
+		} else if (matches(opt, "-stats") == 0 ||
+			   matches(opt, "-statistics") == 0) {
+			++show_stats;
+		} else if (matches(opt, "-details") == 0) {
+			++show_details;
+		} else if (matches(opt, "-oneline") == 0) {
+			++oneline;
+		} else if (matches(opt, "-timestamp") == 0) {
+			++timestamp;
+		} else if (matches(opt, "-family") == 0) {
+			argc--;
+			argv++;
+			if (argc <= 1)
+				usage();
+			if (strcmp(argv[1], "inet") == 0)
+				preferred_family = AF_INET;
+			else if (strcmp(argv[1], "inet6") == 0)
+				preferred_family = AF_INET6;
+			else if (strcmp(argv[1], "help") == 0)
+				usage();
+			else
+				invarg("invalid protocol family", argv[1]);
+		} else if (strcmp(opt, "-4") == 0) {
+			preferred_family = AF_INET;
+		} else if (strcmp(opt, "-6") == 0) {
+			preferred_family = AF_INET6;
+		} else if (matches(opt, "-netns") == 0) {
+			NEXT_ARG();
+			if (netns_switch(argv[1]))
+				exit(-1);
+		} else if (matches(opt, "-compressvlans") == 0) {
+			++compress_vlans;
+		} else if (matches(opt, "-force") == 0) {
+			++force;
+		} else if (matches(opt, "-batch") == 0) {
+			argc--;
+			argv++;
+			if (argc <= 1)
+				usage();
+			batch_file = argv[1];
+		} else {
+			fprintf(stderr,
+				"Option \"%s\" is unknown, try \"bridge help\".\n",
+				opt);
+			exit(-1);
+		}
+		argc--;	argv++;
+	}
+
+	_SL_ = oneline ? "\\" : "\n";
+
+	if (batch_file)
+		return batch(batch_file);
+
+	if (rtnl_open(&rth, 0) < 0)
+		exit(1);
+
+	if (argc > 1)
+		return do_cmd(argv[1], argc-1, argv+1);
+
+	rtnl_close(&rth);
+	usage();
+}
diff --git a/iproute2/bridge/fdb.c b/iproute2/bridge/fdb.c
new file mode 100644
index 0000000..4d10925
--- /dev/null
+++ b/iproute2/bridge/fdb.c
@@ -0,0 +1,400 @@
+/*
+ * Get/set/delete fdb table with netlink
+ *
+ * TODO: merge/replace this with ip neighbour
+ *
+ * Authors:	Stephen Hemminger <shemminger@vyatta.com>
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <netdb.h>
+#include <time.h>
+#include <fcntl.h>
+#include <sys/socket.h>
+#include <sys/time.h>
+#include <net/if.h>
+#include <netinet/in.h>
+#include <linux/if_bridge.h>
+#include <linux/if_ether.h>
+#include <linux/neighbour.h>
+#include <string.h>
+#include <limits.h>
+
+#include "libnetlink.h"
+#include "br_common.h"
+#include "rt_names.h"
+#include "utils.h"
+
+static unsigned int filter_index;
+
+static void usage(void)
+{
+	fprintf(stderr, "Usage: bridge fdb { add | append | del | replace } ADDR dev DEV\n"
+			"              [ self ] [ master ] [ use ] [ router ]\n"
+			"              [ local | temp ] [ dst IPADDR ] [ vlan VID ]\n"
+		        "              [ port PORT] [ vni VNI ] [ via DEV ]\n");
+	fprintf(stderr, "       bridge fdb [ show [ br BRDEV ] [ brport DEV ] ]\n");
+	exit(-1);
+}
+
+static const char *state_n2a(unsigned s)
+{
+	static char buf[32];
+
+	if (s & NUD_PERMANENT)
+		return "permanent";
+
+	if (s & NUD_NOARP)
+		return "static";
+
+	if (s & NUD_STALE)
+		return "stale";
+
+	if (s & NUD_REACHABLE)
+		return "";
+
+	sprintf(buf, "state=%#x", s);
+	return buf;
+}
+
+int print_fdb(const struct sockaddr_nl *who, struct nlmsghdr *n, void *arg)
+{
+	FILE *fp = arg;
+	struct ndmsg *r = NLMSG_DATA(n);
+	int len = n->nlmsg_len;
+	struct rtattr * tb[NDA_MAX+1];
+
+	if (n->nlmsg_type != RTM_NEWNEIGH && n->nlmsg_type != RTM_DELNEIGH) {
+		fprintf(stderr, "Not RTM_NEWNEIGH: %08x %08x %08x\n",
+			n->nlmsg_len, n->nlmsg_type, n->nlmsg_flags);
+
+		return 0;
+	}
+
+	len -= NLMSG_LENGTH(sizeof(*r));
+	if (len < 0) {
+		fprintf(stderr, "BUG: wrong nlmsg len %d\n", len);
+		return -1;
+	}
+
+	if (r->ndm_family != AF_BRIDGE)
+		return 0;
+
+	if (filter_index && filter_index != r->ndm_ifindex)
+		return 0;
+
+	parse_rtattr(tb, NDA_MAX, NDA_RTA(r),
+		     n->nlmsg_len - NLMSG_LENGTH(sizeof(*r)));
+
+	if (n->nlmsg_type == RTM_DELNEIGH)
+		fprintf(fp, "Deleted ");
+
+	if (tb[NDA_LLADDR]) {
+		SPRINT_BUF(b1);
+		fprintf(fp, "%s ",
+			ll_addr_n2a(RTA_DATA(tb[NDA_LLADDR]),
+				    RTA_PAYLOAD(tb[NDA_LLADDR]),
+				    ll_index_to_type(r->ndm_ifindex),
+				    b1, sizeof(b1)));
+	}
+
+	if (!filter_index && r->ndm_ifindex)
+		fprintf(fp, "dev %s ", ll_index_to_name(r->ndm_ifindex));
+
+	if (tb[NDA_DST]) {
+		SPRINT_BUF(abuf);
+		int family = AF_INET;
+
+		if (RTA_PAYLOAD(tb[NDA_DST]) == sizeof(struct in6_addr))
+			family = AF_INET6;
+
+		fprintf(fp, "dst %s ",
+			format_host(family,
+				    RTA_PAYLOAD(tb[NDA_DST]),
+				    RTA_DATA(tb[NDA_DST]),
+				    abuf, sizeof(abuf)));
+	}
+
+	if (tb[NDA_VLAN]) {
+		__u16 vid = rta_getattr_u16(tb[NDA_VLAN]);
+		fprintf(fp, "vlan %hu ", vid);
+	}
+
+	if (tb[NDA_PORT])
+		fprintf(fp, "port %d ", ntohs(rta_getattr_u16(tb[NDA_PORT])));
+	if (tb[NDA_VNI])
+		fprintf(fp, "vni %d ", rta_getattr_u32(tb[NDA_VNI]));
+	if (tb[NDA_IFINDEX]) {
+		unsigned int ifindex = rta_getattr_u32(tb[NDA_IFINDEX]);
+
+		if (ifindex) {
+			char ifname[IF_NAMESIZE];
+
+			if (!tb[NDA_LINK_NETNSID] &&
+			    if_indextoname(ifindex, ifname))
+				fprintf(fp, "via %s ", ifname);
+			else
+				fprintf(fp, "via ifindex %u ", ifindex);
+		}
+	}
+	if (tb[NDA_LINK_NETNSID])
+		fprintf(fp, "link-netnsid %d ",
+			rta_getattr_u32(tb[NDA_LINK_NETNSID]));
+
+	if (show_stats && tb[NDA_CACHEINFO]) {
+		struct nda_cacheinfo *ci = RTA_DATA(tb[NDA_CACHEINFO]);
+		int hz = get_user_hz();
+
+		fprintf(fp, "used %d/%d ", ci->ndm_used/hz,
+		       ci->ndm_updated/hz);
+	}
+	if (r->ndm_flags & NTF_SELF)
+		fprintf(fp, "self ");
+	if (tb[NDA_MASTER])
+		fprintf(fp, "master %s ",
+			ll_index_to_name(rta_getattr_u32(tb[NDA_MASTER])));
+	else if (r->ndm_flags & NTF_MASTER)
+		fprintf(fp, "master ");
+	if (r->ndm_flags & NTF_ROUTER)
+		fprintf(fp, "router ");
+	if (r->ndm_flags & NTF_EXT_LEARNED)
+		fprintf(fp, "offload ");
+
+	fprintf(fp, "%s\n", state_n2a(r->ndm_state));
+	fflush(fp);
+
+	return 0;
+}
+
+static int fdb_show(int argc, char **argv)
+{
+	struct {
+		struct nlmsghdr 	n;
+		struct ifinfomsg	ifm;
+		char   			buf[256];
+	} req;
+
+	char *filter_dev = NULL;
+	char *br = NULL;
+	int msg_size = sizeof(struct ifinfomsg);
+
+	memset(&req, 0, sizeof(req));
+	req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg));
+	req.ifm.ifi_family = PF_BRIDGE;
+
+	while (argc > 0) {
+		if ((strcmp(*argv, "brport") == 0) || strcmp(*argv, "dev") == 0) {
+			NEXT_ARG();
+			filter_dev = *argv;
+		} else if (strcmp(*argv, "br") == 0) {
+			NEXT_ARG();
+			br = *argv;
+		} else {
+			if (matches(*argv, "help") == 0)
+				usage();
+		}
+		argc--; argv++;
+	}
+
+	if (br) {
+		int br_ifindex = ll_name_to_index(br);
+		if (br_ifindex == 0) {
+			fprintf(stderr, "Cannot find bridge device \"%s\"\n", br);
+			return -1;
+		}
+		addattr32(&req.n, sizeof(req), IFLA_MASTER, br_ifindex);
+		msg_size += RTA_LENGTH(4);
+	}
+
+	/*we'll keep around filter_dev for older kernels */
+	if (filter_dev) {
+		filter_index = if_nametoindex(filter_dev);
+		if (filter_index == 0) {
+			fprintf(stderr, "Cannot find device \"%s\"\n",
+				filter_dev);
+			return -1;
+		}
+		req.ifm.ifi_index = filter_index;
+	}
+
+	if (rtnl_dump_request(&rth, RTM_GETNEIGH, &req.ifm, msg_size) < 0) {
+		perror("Cannot send dump request");
+		exit(1);
+	}
+
+	if (rtnl_dump_filter(&rth, print_fdb, stdout) < 0) {
+		fprintf(stderr, "Dump terminated\n");
+		exit(1);
+	}
+
+	return 0;
+}
+
+static int fdb_modify(int cmd, int flags, int argc, char **argv)
+{
+	struct {
+		struct nlmsghdr 	n;
+		struct ndmsg 		ndm;
+		char   			buf[256];
+	} req;
+	char *addr = NULL;
+	char *d = NULL;
+	char abuf[ETH_ALEN];
+	int dst_ok = 0;
+	inet_prefix dst;
+	unsigned long port = 0;
+	unsigned long vni = ~0;
+	unsigned int via = 0;
+	char *endptr;
+	short vid = -1;
+
+	memset(&req, 0, sizeof(req));
+
+	req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct ndmsg));
+	req.n.nlmsg_flags = NLM_F_REQUEST|flags;
+	req.n.nlmsg_type = cmd;
+	req.ndm.ndm_family = PF_BRIDGE;
+	req.ndm.ndm_state = NUD_NOARP;
+
+	while (argc > 0) {
+		if (strcmp(*argv, "dev") == 0) {
+			NEXT_ARG();
+			d = *argv;
+		} else if (strcmp(*argv, "dst") == 0) {
+			NEXT_ARG();
+			if (dst_ok)
+				duparg2("dst", *argv);
+			get_addr(&dst, *argv, preferred_family);
+			dst_ok = 1;
+		} else if (strcmp(*argv, "port") == 0) {
+
+			NEXT_ARG();
+			port = strtoul(*argv, &endptr, 0);
+			if (endptr && *endptr) {
+				struct servent *pse;
+
+				pse = getservbyname(*argv, "udp");
+				if (!pse)
+					invarg("invalid port\n", *argv);
+				port = ntohs(pse->s_port);
+			} else if (port > 0xffff)
+				invarg("invalid port\n", *argv);
+		} else if (strcmp(*argv, "vni") == 0) {
+			NEXT_ARG();
+			vni = strtoul(*argv, &endptr, 0);
+			if ((endptr && *endptr) ||
+			    (vni >> 24) || vni == ULONG_MAX)
+				invarg("invalid VNI\n", *argv);
+		} else if (strcmp(*argv, "via") == 0) {
+			NEXT_ARG();
+			via = if_nametoindex(*argv);
+			if (via == 0)
+				invarg("invalid device\n", *argv);
+		} else if (strcmp(*argv, "self") == 0) {
+			req.ndm.ndm_flags |= NTF_SELF;
+		} else if (matches(*argv, "master") == 0) {
+			req.ndm.ndm_flags |= NTF_MASTER;
+		} else if (matches(*argv, "router") == 0) {
+			req.ndm.ndm_flags |= NTF_ROUTER;
+		} else if (matches(*argv, "local") == 0||
+			   matches(*argv, "permanent") == 0) {
+			req.ndm.ndm_state |= NUD_PERMANENT;
+		} else if (matches(*argv, "temp") == 0) {
+			req.ndm.ndm_state |= NUD_REACHABLE;
+		} else if (matches(*argv, "vlan") == 0) {
+			if (vid >= 0)
+				duparg2("vlan", *argv);
+			NEXT_ARG();
+			vid = atoi(*argv);
+		} else if (matches(*argv, "use") == 0) {
+			req.ndm.ndm_flags |= NTF_USE;
+		} else {
+			if (strcmp(*argv, "to") == 0) {
+				NEXT_ARG();
+			}
+			if (matches(*argv, "help") == 0)
+				usage();
+			if (addr)
+				duparg2("to", *argv);
+			addr = *argv;
+		}
+		argc--; argv++;
+	}
+
+	if (d == NULL || addr == NULL) {
+		fprintf(stderr, "Device and address are required arguments.\n");
+		return -1;
+	}
+
+	/* Assume self */
+	if (!(req.ndm.ndm_flags&(NTF_SELF|NTF_MASTER)))
+		req.ndm.ndm_flags |= NTF_SELF;
+
+	/* Assume permanent */
+	if (!(req.ndm.ndm_state&(NUD_PERMANENT|NUD_REACHABLE)))
+		req.ndm.ndm_state |= NUD_PERMANENT;
+
+	if (sscanf(addr, "%hhx:%hhx:%hhx:%hhx:%hhx:%hhx",
+		   abuf, abuf+1, abuf+2,
+		   abuf+3, abuf+4, abuf+5) != 6) {
+		fprintf(stderr, "Invalid mac address %s\n", addr);
+		return -1;
+	}
+
+	addattr_l(&req.n, sizeof(req), NDA_LLADDR, abuf, ETH_ALEN);
+	if (dst_ok)
+		addattr_l(&req.n, sizeof(req), NDA_DST, &dst.data, dst.bytelen);
+
+	if (vid >= 0)
+		addattr16(&req.n, sizeof(req), NDA_VLAN, vid);
+
+	if (port) {
+		unsigned short dport;
+
+		dport = htons((unsigned short)port);
+		addattr16(&req.n, sizeof(req), NDA_PORT, dport);
+	}
+	if (vni != ~0)
+		addattr32(&req.n, sizeof(req), NDA_VNI, vni);
+	if (via)
+		addattr32(&req.n, sizeof(req), NDA_IFINDEX, via);
+
+	req.ndm.ndm_ifindex = ll_name_to_index(d);
+	if (req.ndm.ndm_ifindex == 0) {
+		fprintf(stderr, "Cannot find device \"%s\"\n", d);
+		return -1;
+	}
+
+	if (rtnl_talk(&rth, &req.n, NULL, 0) < 0)
+		return -1;
+
+	return 0;
+}
+
+int do_fdb(int argc, char **argv)
+{
+	ll_init_map(&rth);
+
+	if (argc > 0) {
+		if (matches(*argv, "add") == 0)
+			return fdb_modify(RTM_NEWNEIGH, NLM_F_CREATE|NLM_F_EXCL, argc-1, argv+1);
+		if (matches(*argv, "append") == 0)
+			return fdb_modify(RTM_NEWNEIGH, NLM_F_CREATE|NLM_F_APPEND, argc-1, argv+1);
+		if (matches(*argv, "replace") == 0)
+			return fdb_modify(RTM_NEWNEIGH, NLM_F_CREATE|NLM_F_REPLACE, argc-1, argv+1);
+		if (matches(*argv, "delete") == 0)
+			return fdb_modify(RTM_DELNEIGH, 0, argc-1, argv+1);
+		if (matches(*argv, "show") == 0 ||
+		    matches(*argv, "lst") == 0 ||
+		    matches(*argv, "list") == 0)
+			return fdb_show(argc-1, argv+1);
+		if (matches(*argv, "help") == 0)
+			usage();
+	} else
+		return fdb_show(0, NULL);
+
+	fprintf(stderr, "Command \"%s\" is unknown, try \"bridge fdb help\".\n", *argv);
+	exit(-1);
+}
diff --git a/iproute2/bridge/link.c b/iproute2/bridge/link.c
new file mode 100644
index 0000000..a9b1262
--- /dev/null
+++ b/iproute2/bridge/link.c
@@ -0,0 +1,476 @@
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <time.h>
+#include <sys/socket.h>
+#include <sys/time.h>
+#include <netinet/in.h>
+#include <linux/if.h>
+#include <linux/if_bridge.h>
+#include <string.h>
+#include <stdbool.h>
+
+#include "libnetlink.h"
+#include "utils.h"
+#include "br_common.h"
+
+static unsigned int filter_index;
+
+static const char *port_states[] = {
+	[BR_STATE_DISABLED] = "disabled",
+	[BR_STATE_LISTENING] = "listening",
+	[BR_STATE_LEARNING] = "learning",
+	[BR_STATE_FORWARDING] = "forwarding",
+	[BR_STATE_BLOCKING] = "blocking",
+};
+
+extern char *if_indextoname (unsigned int __ifindex, char *__ifname);
+
+static void print_link_flags(FILE *fp, unsigned flags)
+{
+	fprintf(fp, "<");
+	if (flags & IFF_UP && !(flags & IFF_RUNNING))
+		fprintf(fp, "NO-CARRIER%s", flags ? "," : "");
+	flags &= ~IFF_RUNNING;
+#define _PF(f) if (flags&IFF_##f) { \
+                  flags &= ~IFF_##f ; \
+                  fprintf(fp, #f "%s", flags ? "," : ""); }
+	_PF(LOOPBACK);
+	_PF(BROADCAST);
+	_PF(POINTOPOINT);
+	_PF(MULTICAST);
+	_PF(NOARP);
+	_PF(ALLMULTI);
+	_PF(PROMISC);
+	_PF(MASTER);
+	_PF(SLAVE);
+	_PF(DEBUG);
+	_PF(DYNAMIC);
+	_PF(AUTOMEDIA);
+	_PF(PORTSEL);
+	_PF(NOTRAILERS);
+	_PF(UP);
+	_PF(LOWER_UP);
+	_PF(DORMANT);
+	_PF(ECHO);
+#undef _PF
+        if (flags)
+		fprintf(fp, "%x", flags);
+	fprintf(fp, "> ");
+}
+
+static const char *oper_states[] = {
+	"UNKNOWN", "NOTPRESENT", "DOWN", "LOWERLAYERDOWN",
+	"TESTING", "DORMANT",	 "UP"
+};
+
+static const char *hw_mode[] = {"VEB", "VEPA"};
+
+static void print_operstate(FILE *f, __u8 state)
+{
+	if (state >= sizeof(oper_states)/sizeof(oper_states[0]))
+		fprintf(f, "state %#x ", state);
+	else
+		fprintf(f, "state %s ", oper_states[state]);
+}
+
+static void print_portstate(FILE *f, __u8 state)
+{
+	if (state <= BR_STATE_BLOCKING)
+		fprintf(f, "state %s ", port_states[state]);
+	else
+		fprintf(f, "state (%d) ", state);
+}
+
+static void print_onoff(FILE *f, char *flag, __u8 val)
+{
+	fprintf(f, "%s %s ", flag, val ? "on" : "off");
+}
+
+static void print_hwmode(FILE *f, __u16 mode)
+{
+	if (mode >= sizeof(hw_mode)/sizeof(hw_mode[0]))
+		fprintf(f, "hwmode %#hx ", mode);
+	else
+		fprintf(f, "hwmode %s ", hw_mode[mode]);
+}
+
+int print_linkinfo(const struct sockaddr_nl *who,
+		   struct nlmsghdr *n, void *arg)
+{
+	FILE *fp = arg;
+	int len = n->nlmsg_len;
+	struct ifinfomsg *ifi = NLMSG_DATA(n);
+	struct rtattr * tb[IFLA_MAX+1];
+	char b1[IFNAMSIZ];
+
+	len -= NLMSG_LENGTH(sizeof(*ifi));
+	if (len < 0) {
+		fprintf(stderr, "Message too short!\n");
+		return -1;
+        }
+
+	if (!(ifi->ifi_family == AF_BRIDGE || ifi->ifi_family == AF_UNSPEC))
+		return 0;
+
+	if (filter_index && filter_index != ifi->ifi_index)
+		return 0;
+
+	parse_rtattr_flags(tb, IFLA_MAX, IFLA_RTA(ifi), len, NLA_F_NESTED);
+
+	if (tb[IFLA_IFNAME] == NULL) {
+		fprintf(stderr, "BUG: nil ifname\n");
+		return -1;
+	}
+
+	if (n->nlmsg_type == RTM_DELLINK)
+		fprintf(fp, "Deleted ");
+
+	fprintf(fp, "%d: %s ", ifi->ifi_index,
+		tb[IFLA_IFNAME] ? rta_getattr_str(tb[IFLA_IFNAME]) : "<nil>");
+
+	if (tb[IFLA_OPERSTATE])
+		print_operstate(fp, rta_getattr_u8(tb[IFLA_OPERSTATE]));
+
+	if (tb[IFLA_LINK]) {
+		SPRINT_BUF(b1);
+		int iflink = rta_getattr_u32(tb[IFLA_LINK]);
+		if (iflink == 0)
+			fprintf(fp, "@NONE: ");
+		else
+			fprintf(fp, "@%s: ",
+				if_indextoname(iflink, b1));
+	} else
+		fprintf(fp, ": ");
+
+	print_link_flags(fp, ifi->ifi_flags);
+
+	if (tb[IFLA_MTU])
+		fprintf(fp, "mtu %u ", rta_getattr_u32(tb[IFLA_MTU]));
+
+	if (tb[IFLA_MASTER])
+		fprintf(fp, "master %s ",
+			if_indextoname(rta_getattr_u32(tb[IFLA_MASTER]), b1));
+
+	if (tb[IFLA_PROTINFO]) {
+		if (tb[IFLA_PROTINFO]->rta_type & NLA_F_NESTED) {
+			struct rtattr *prtb[IFLA_BRPORT_MAX+1];
+
+			parse_rtattr_nested(prtb, IFLA_BRPORT_MAX,
+					    tb[IFLA_PROTINFO]);
+
+			if (prtb[IFLA_BRPORT_STATE])
+				print_portstate(fp,
+						rta_getattr_u8(prtb[IFLA_BRPORT_STATE]));
+			if (prtb[IFLA_BRPORT_PRIORITY])
+				fprintf(fp, "priority %hu ",
+					rta_getattr_u16(prtb[IFLA_BRPORT_PRIORITY]));
+			if (prtb[IFLA_BRPORT_COST])
+				fprintf(fp, "cost %u ",
+					rta_getattr_u32(prtb[IFLA_BRPORT_COST]));
+
+			if (show_details) {
+				fprintf(fp, "%s    ", _SL_);
+
+				if (prtb[IFLA_BRPORT_MODE])
+					print_onoff(fp, "hairpin",
+						    rta_getattr_u8(prtb[IFLA_BRPORT_MODE]));
+				if (prtb[IFLA_BRPORT_GUARD])
+					print_onoff(fp, "guard",
+						    rta_getattr_u8(prtb[IFLA_BRPORT_GUARD]));
+				if (prtb[IFLA_BRPORT_PROTECT])
+					print_onoff(fp, "root_block",
+						    rta_getattr_u8(prtb[IFLA_BRPORT_PROTECT]));
+				if (prtb[IFLA_BRPORT_FAST_LEAVE])
+					print_onoff(fp, "fastleave",
+						    rta_getattr_u8(prtb[IFLA_BRPORT_FAST_LEAVE]));
+				if (prtb[IFLA_BRPORT_LEARNING])
+					print_onoff(fp, "learning",
+						    rta_getattr_u8(prtb[IFLA_BRPORT_LEARNING]));
+				if (prtb[IFLA_BRPORT_LEARNING_SYNC])
+					print_onoff(fp, "learning_sync",
+						    rta_getattr_u8(prtb[IFLA_BRPORT_LEARNING_SYNC]));
+				if (prtb[IFLA_BRPORT_UNICAST_FLOOD])
+					print_onoff(fp, "flood",
+						    rta_getattr_u8(prtb[IFLA_BRPORT_UNICAST_FLOOD]));
+			}
+		} else
+			print_portstate(fp, rta_getattr_u8(tb[IFLA_PROTINFO]));
+	}
+
+	if (tb[IFLA_AF_SPEC]) {
+		/* This is reported by HW devices that have some bridging
+		 * capabilities.
+		 */
+		struct rtattr *aftb[IFLA_BRIDGE_MAX+1];
+
+		parse_rtattr_nested(aftb, IFLA_BRIDGE_MAX, tb[IFLA_AF_SPEC]);
+
+		if (aftb[IFLA_BRIDGE_MODE])
+			print_hwmode(fp, rta_getattr_u16(aftb[IFLA_BRIDGE_MODE]));
+	}
+
+	fprintf(fp, "\n");
+	fflush(fp);
+	return 0;
+}
+
+static void usage(void)
+{
+	fprintf(stderr, "Usage: bridge link set dev DEV [ cost COST ] [ priority PRIO ] [ state STATE ]\n");
+	fprintf(stderr, "                               [ guard {on | off} ]\n");
+	fprintf(stderr, "                               [ hairpin {on | off} ] \n");
+	fprintf(stderr, "                               [ fastleave {on | off} ]\n");
+	fprintf(stderr,	"                               [ root_block {on | off} ]\n");
+	fprintf(stderr,	"                               [ learning {on | off} ]\n");
+	fprintf(stderr,	"                               [ learning_sync {on | off} ]\n");
+	fprintf(stderr,	"                               [ flood {on | off} ]\n");
+	fprintf(stderr, "                               [ hwmode {vepa | veb} ]\n");
+	fprintf(stderr, "                               [ self ] [ master ]\n");
+	fprintf(stderr, "       bridge link show [dev DEV]\n");
+	exit(-1);
+}
+
+static bool on_off(char *arg, __s8 *attr, char *val)
+{
+	if (strcmp(val, "on") == 0)
+		*attr = 1;
+	else if (strcmp(val, "off") == 0)
+		*attr = 0;
+	else {
+		fprintf(stderr,
+			"Error: argument of \"%s\" must be \"on\" or \"off\"\n",
+			arg);
+		return false;
+	}
+
+	return true;
+}
+
+static int brlink_modify(int argc, char **argv)
+{
+	struct {
+		struct nlmsghdr  n;
+		struct ifinfomsg ifm;
+		char             buf[512];
+	} req;
+	char *d = NULL;
+	__s8 learning = -1;
+	__s8 learning_sync = -1;
+	__s8 flood = -1;
+	__s8 hairpin = -1;
+	__s8 bpdu_guard = -1;
+	__s8 fast_leave = -1;
+	__s8 root_block = -1;
+	__u32 cost = 0;
+	__s16 priority = -1;
+	__s8 state = -1;
+	__s16 mode = -1;
+	__u16 flags = 0;
+	struct rtattr *nest;
+
+	memset(&req, 0, sizeof(req));
+
+	req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg));
+	req.n.nlmsg_flags = NLM_F_REQUEST;
+	req.n.nlmsg_type = RTM_SETLINK;
+	req.ifm.ifi_family = PF_BRIDGE;
+
+	while (argc > 0) {
+		if (strcmp(*argv, "dev") == 0) {
+			NEXT_ARG();
+			d = *argv;
+		} else if (strcmp(*argv, "guard") == 0) {
+			NEXT_ARG();
+			if (!on_off("guard", &bpdu_guard, *argv))
+				return -1;
+		} else if (strcmp(*argv, "hairpin") == 0) {
+			NEXT_ARG();
+			if (!on_off("hairping", &hairpin, *argv))
+				return -1;
+		} else if (strcmp(*argv, "fastleave") == 0) {
+			NEXT_ARG();
+			if (!on_off("fastleave", &fast_leave, *argv))
+				return -1;
+		} else if (strcmp(*argv, "root_block") == 0) {
+			NEXT_ARG();
+			if (!on_off("root_block", &root_block, *argv))
+				return -1;
+		} else if (strcmp(*argv, "learning") == 0) {
+			NEXT_ARG();
+			if (!on_off("learning", &learning, *argv))
+				return -1;
+		} else if (strcmp(*argv, "learning_sync") == 0) {
+			NEXT_ARG();
+			if (!on_off("learning_sync", &learning_sync, *argv))
+				return -1;
+		} else if (strcmp(*argv, "flood") == 0) {
+			NEXT_ARG();
+			if (!on_off("flood", &flood, *argv))
+				return -1;
+		} else if (strcmp(*argv, "cost") == 0) {
+			NEXT_ARG();
+			cost = atoi(*argv);
+		} else if (strcmp(*argv, "priority") == 0) {
+			NEXT_ARG();
+			priority = atoi(*argv);
+		} else if (strcmp(*argv, "state") == 0) {
+			NEXT_ARG();
+			char *endptr;
+			size_t nstates = sizeof(port_states) / sizeof(*port_states);
+			state = strtol(*argv, &endptr, 10);
+			if (!(**argv != '\0' && *endptr == '\0')) {
+				for (state = 0; state < nstates; state++)
+					if (strcmp(port_states[state], *argv) == 0)
+						break;
+				if (state == nstates) {
+					fprintf(stderr,
+						"Error: invalid STP port state\n");
+					return -1;
+				}
+			}
+		} else if (strcmp(*argv, "hwmode") == 0) {
+			NEXT_ARG();
+			flags = BRIDGE_FLAGS_SELF;
+			if (strcmp(*argv, "vepa") == 0)
+				mode = BRIDGE_MODE_VEPA;
+			else if (strcmp(*argv, "veb") == 0)
+				mode = BRIDGE_MODE_VEB;
+			else {
+				fprintf(stderr,
+					"Mode argument must be \"vepa\" or "
+					"\"veb\".\n");
+				return -1;
+			}
+		} else if (strcmp(*argv, "self") == 0) {
+			flags |= BRIDGE_FLAGS_SELF;
+		} else if (strcmp(*argv, "master") == 0) {
+			flags |= BRIDGE_FLAGS_MASTER;
+		} else {
+			usage();
+		}
+		argc--; argv++;
+	}
+	if (d == NULL) {
+		fprintf(stderr, "Device is a required argument.\n");
+		return -1;
+	}
+
+
+	req.ifm.ifi_index = ll_name_to_index(d);
+	if (req.ifm.ifi_index == 0) {
+		fprintf(stderr, "Cannot find bridge device \"%s\"\n", d);
+		return -1;
+	}
+
+	/* Nested PROTINFO attribute.  Contains: port flags, cost, priority and
+	 * state.
+	 */
+	nest = addattr_nest(&req.n, sizeof(req),
+			    IFLA_PROTINFO | NLA_F_NESTED);
+	/* Flags first */
+	if (bpdu_guard >= 0)
+		addattr8(&req.n, sizeof(req), IFLA_BRPORT_GUARD, bpdu_guard);
+	if (hairpin >= 0)
+		addattr8(&req.n, sizeof(req), IFLA_BRPORT_MODE, hairpin);
+	if (fast_leave >= 0)
+		addattr8(&req.n, sizeof(req), IFLA_BRPORT_FAST_LEAVE,
+			 fast_leave);
+	if (root_block >= 0)
+		addattr8(&req.n, sizeof(req), IFLA_BRPORT_PROTECT, root_block);
+	if (flood >= 0)
+		addattr8(&req.n, sizeof(req), IFLA_BRPORT_UNICAST_FLOOD, flood);
+	if (learning >= 0)
+		addattr8(&req.n, sizeof(req), IFLA_BRPORT_LEARNING, learning);
+	if (learning_sync >= 0)
+		addattr8(&req.n, sizeof(req), IFLA_BRPORT_LEARNING_SYNC,
+			 learning_sync);
+
+	if (cost > 0)
+		addattr32(&req.n, sizeof(req), IFLA_BRPORT_COST, cost);
+
+	if (priority >= 0)
+		addattr16(&req.n, sizeof(req), IFLA_BRPORT_PRIORITY, priority);
+
+	if (state >= 0)
+		addattr8(&req.n, sizeof(req), IFLA_BRPORT_STATE, state);
+
+	addattr_nest_end(&req.n, nest);
+
+	/* IFLA_AF_SPEC nested attribute. Contains IFLA_BRIDGE_FLAGS that
+	 * designates master or self operation and IFLA_BRIDGE_MODE
+	 * for hw 'vepa' or 'veb' operation modes. The hwmodes are
+	 * only valid in 'self' mode on some devices so far.
+	 */
+	if (mode >= 0 || flags > 0) {
+		nest = addattr_nest(&req.n, sizeof(req), IFLA_AF_SPEC);
+
+		if (flags > 0)
+			addattr16(&req.n, sizeof(req), IFLA_BRIDGE_FLAGS, flags);
+
+		if (mode >= 0)
+			addattr16(&req.n, sizeof(req), IFLA_BRIDGE_MODE, mode);
+
+		addattr_nest_end(&req.n, nest);
+	}
+
+	if (rtnl_talk(&rth, &req.n, NULL, 0) < 0)
+		return -1;
+
+	return 0;
+}
+
+static int brlink_show(int argc, char **argv)
+{
+	char *filter_dev = NULL;
+
+	while (argc > 0) {
+		if (strcmp(*argv, "dev") == 0) {
+			NEXT_ARG();
+			if (filter_dev)
+				duparg("dev", *argv);
+			filter_dev = *argv;
+		}
+		argc--; argv++;
+	}
+
+	if (filter_dev) {
+		if ((filter_index = ll_name_to_index(filter_dev)) == 0) {
+			fprintf(stderr, "Cannot find device \"%s\"\n",
+				filter_dev);
+			return -1;
+		}
+	}
+
+	if (rtnl_wilddump_request(&rth, PF_BRIDGE, RTM_GETLINK) < 0) {
+		perror("Cannon send dump request");
+		exit(1);
+	}
+
+	if (rtnl_dump_filter(&rth, print_linkinfo, stdout) < 0) {
+		fprintf(stderr, "Dump terminated\n");
+		exit(1);
+	}
+	return 0;
+}
+
+int do_link(int argc, char **argv)
+{
+	ll_init_map(&rth);
+	if (argc > 0) {
+		if (matches(*argv, "set") == 0 ||
+		    matches(*argv, "change") == 0)
+			return brlink_modify(argc-1, argv+1);
+		if (matches(*argv, "show") == 0 ||
+		    matches(*argv, "lst") == 0 ||
+		    matches(*argv, "list") == 0)
+			return brlink_show(argc-1, argv+1);
+		if (matches(*argv, "help") == 0)
+			usage();
+	} else
+		return brlink_show(0, NULL);
+
+	fprintf(stderr, "Command \"%s\" is unknown, try \"bridge link help\".\n", *argv);
+	exit(-1);
+}
diff --git a/iproute2/bridge/mdb.c b/iproute2/bridge/mdb.c
new file mode 100644
index 0000000..24c4903
--- /dev/null
+++ b/iproute2/bridge/mdb.c
@@ -0,0 +1,279 @@
+/*
+ * Get mdb table with netlink
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <sys/socket.h>
+#include <net/if.h>
+#include <netinet/in.h>
+#include <linux/if_bridge.h>
+#include <linux/if_ether.h>
+#include <string.h>
+#include <arpa/inet.h>
+
+#include "libnetlink.h"
+#include "br_common.h"
+#include "rt_names.h"
+#include "utils.h"
+
+#ifndef MDBA_RTA
+#define MDBA_RTA(r) \
+	((struct rtattr*)(((char*)(r)) + NLMSG_ALIGN(sizeof(struct br_port_msg))))
+#endif
+
+static unsigned int filter_index;
+
+static void usage(void)
+{
+	fprintf(stderr, "Usage: bridge mdb { add | del } dev DEV port PORT grp GROUP [permanent | temp] [vid VID]\n");
+	fprintf(stderr, "       bridge mdb {show} [ dev DEV ]\n");
+	exit(-1);
+}
+
+static void br_print_router_ports(FILE *f, struct rtattr *attr)
+{
+	uint32_t *port_ifindex;
+	struct rtattr *i;
+	int rem;
+
+	rem = RTA_PAYLOAD(attr);
+	for (i = RTA_DATA(attr); RTA_OK(i, rem); i = RTA_NEXT(i, rem)) {
+		port_ifindex = RTA_DATA(i);
+		fprintf(f, "%s ", ll_index_to_name(*port_ifindex));
+	}
+
+	fprintf(f, "\n");
+}
+
+static void print_mdb_entry(FILE *f, int ifindex, struct br_mdb_entry *e,
+			    struct nlmsghdr *n)
+{
+	SPRINT_BUF(abuf);
+	const void *src;
+	int af;
+
+	af = e->addr.proto == htons(ETH_P_IP) ? AF_INET : AF_INET6;
+	src = af == AF_INET ? (const void *)&e->addr.u.ip4 :
+			      (const void *)&e->addr.u.ip6;
+	if (n->nlmsg_type == RTM_DELMDB)
+		fprintf(f, "Deleted ");
+	fprintf(f, "dev %s port %s grp %s %s", ll_index_to_name(ifindex),
+		ll_index_to_name(e->ifindex),
+		inet_ntop(af, src, abuf, sizeof(abuf)),
+		(e->state & MDB_PERMANENT) ? "permanent" : "temp");
+	if (e->vid)
+		fprintf(f, " vid %hu", e->vid);
+	fprintf(f, "\n");
+}
+
+static void br_print_mdb_entry(FILE *f, int ifindex, struct rtattr *attr,
+			       struct nlmsghdr *n)
+{
+	struct rtattr *i;
+	int rem;
+	struct br_mdb_entry *e;
+
+	rem = RTA_PAYLOAD(attr);
+	for (i = RTA_DATA(attr); RTA_OK(i, rem); i = RTA_NEXT(i, rem)) {
+		e = RTA_DATA(i);
+		print_mdb_entry(f, ifindex, e, n);
+	}
+}
+
+int print_mdb(const struct sockaddr_nl *who, struct nlmsghdr *n, void *arg)
+{
+	FILE *fp = arg;
+	struct br_port_msg *r = NLMSG_DATA(n);
+	int len = n->nlmsg_len;
+	struct rtattr *tb[MDBA_MAX+1], *i;
+
+	if (n->nlmsg_type != RTM_GETMDB && n->nlmsg_type != RTM_NEWMDB && n->nlmsg_type != RTM_DELMDB) {
+		fprintf(stderr, "Not RTM_GETMDB, RTM_NEWMDB or RTM_DELMDB: %08x %08x %08x\n",
+			n->nlmsg_len, n->nlmsg_type, n->nlmsg_flags);
+
+		return 0;
+	}
+
+	len -= NLMSG_LENGTH(sizeof(*r));
+	if (len < 0) {
+		fprintf(stderr, "BUG: wrong nlmsg len %d\n", len);
+		return -1;
+	}
+
+	if (filter_index && filter_index != r->ifindex)
+		return 0;
+
+	parse_rtattr(tb, MDBA_MAX, MDBA_RTA(r), n->nlmsg_len - NLMSG_LENGTH(sizeof(*r)));
+
+	if (tb[MDBA_MDB]) {
+		int rem = RTA_PAYLOAD(tb[MDBA_MDB]);
+
+		for (i = RTA_DATA(tb[MDBA_MDB]); RTA_OK(i, rem); i = RTA_NEXT(i, rem))
+			br_print_mdb_entry(fp, r->ifindex, i, n);
+	}
+
+	if (tb[MDBA_ROUTER]) {
+		if (n->nlmsg_type == RTM_GETMDB) {
+			if (show_details) {
+				fprintf(fp, "router ports on %s: ",
+					ll_index_to_name(r->ifindex));
+				br_print_router_ports(fp, tb[MDBA_ROUTER]);
+			}
+		} else {
+			uint32_t *port_ifindex;
+
+			i = RTA_DATA(tb[MDBA_ROUTER]);
+			port_ifindex = RTA_DATA(i);
+			if (n->nlmsg_type == RTM_DELMDB)
+				fprintf(fp, "Deleted ");
+			fprintf(fp, "router port dev %s master %s\n",
+				ll_index_to_name(*port_ifindex),
+				ll_index_to_name(r->ifindex));
+		}
+	}
+
+	fflush(fp);
+
+	return 0;
+}
+
+static int mdb_show(int argc, char **argv)
+{
+	char *filter_dev = NULL;
+
+	while (argc > 0) {
+		if (strcmp(*argv, "dev") == 0) {
+			NEXT_ARG();
+			if (filter_dev)
+				duparg("dev", *argv);
+			filter_dev = *argv;
+		}
+		argc--; argv++;
+	}
+
+	if (filter_dev) {
+		filter_index = if_nametoindex(filter_dev);
+		if (filter_index == 0) {
+			fprintf(stderr, "Cannot find device \"%s\"\n",
+				filter_dev);
+			return -1;
+		}
+	}
+
+	if (rtnl_wilddump_request(&rth, PF_BRIDGE, RTM_GETMDB) < 0) {
+		perror("Cannot send dump request");
+		return -1;
+	}
+
+	if (rtnl_dump_filter(&rth, print_mdb, stdout) < 0) {
+		fprintf(stderr, "Dump terminated\n");
+		return -1;
+	}
+
+	return 0;
+}
+
+static int mdb_modify(int cmd, int flags, int argc, char **argv)
+{
+	struct {
+		struct nlmsghdr 	n;
+		struct br_port_msg	bpm;
+		char   			buf[1024];
+	} req;
+	struct br_mdb_entry entry;
+	char *d = NULL, *p = NULL, *grp = NULL;
+	short vid = 0;
+
+	memset(&req, 0, sizeof(req));
+	memset(&entry, 0, sizeof(entry));
+
+	req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct br_port_msg));
+	req.n.nlmsg_flags = NLM_F_REQUEST|flags;
+	req.n.nlmsg_type = cmd;
+	req.bpm.family = PF_BRIDGE;
+
+	while (argc > 0) {
+		if (strcmp(*argv, "dev") == 0) {
+			NEXT_ARG();
+			d = *argv;
+		} else if (strcmp(*argv, "grp") == 0) {
+			NEXT_ARG();
+			grp = *argv;
+		} else if (strcmp(*argv, "port") == 0) {
+			NEXT_ARG();
+			p = *argv;
+		} else if (strcmp(*argv, "permanent") == 0) {
+			if (cmd == RTM_NEWMDB)
+				entry.state |= MDB_PERMANENT;
+		} else if (strcmp(*argv, "temp") == 0) {
+			;/* nothing */
+		} else if (strcmp(*argv, "vid") == 0) {
+			NEXT_ARG();
+			vid = atoi(*argv);
+		} else {
+			if (matches(*argv, "help") == 0)
+				usage();
+		}
+		argc--; argv++;
+	}
+
+	if (d == NULL || grp == NULL || p == NULL) {
+		fprintf(stderr, "Device, group address and port name are required arguments.\n");
+		return -1;
+	}
+
+	req.bpm.ifindex = ll_name_to_index(d);
+	if (req.bpm.ifindex == 0) {
+		fprintf(stderr, "Cannot find device \"%s\"\n", d);
+		return -1;
+	}
+
+	entry.ifindex = ll_name_to_index(p);
+	if (entry.ifindex == 0) {
+		fprintf(stderr, "Cannot find device \"%s\"\n", p);
+		return -1;
+	}
+
+	if (!inet_pton(AF_INET, grp, &entry.addr.u.ip4)) {
+		if (!inet_pton(AF_INET6, grp, &entry.addr.u.ip6)) {
+			fprintf(stderr, "Invalid address \"%s\"\n", grp);
+			return -1;
+		} else
+			entry.addr.proto = htons(ETH_P_IPV6);
+	} else
+		entry.addr.proto = htons(ETH_P_IP);
+
+	entry.vid = vid;
+	addattr_l(&req.n, sizeof(req), MDBA_SET_ENTRY, &entry, sizeof(entry));
+
+	if (rtnl_talk(&rth, &req.n, NULL, 0) < 0)
+		return -1;
+
+	return 0;
+}
+
+int do_mdb(int argc, char **argv)
+{
+	ll_init_map(&rth);
+
+	if (argc > 0) {
+		if (matches(*argv, "add") == 0)
+			return mdb_modify(RTM_NEWMDB, NLM_F_CREATE|NLM_F_EXCL, argc-1, argv+1);
+		if (matches(*argv, "delete") == 0)
+			return mdb_modify(RTM_DELMDB, 0, argc-1, argv+1);
+
+		if (matches(*argv, "show") == 0 ||
+		    matches(*argv, "lst") == 0 ||
+		    matches(*argv, "list") == 0)
+			return mdb_show(argc-1, argv+1);
+		if (matches(*argv, "help") == 0)
+			usage();
+	} else
+		return mdb_show(0, NULL);
+
+	fprintf(stderr, "Command \"%s\" is unknown, try \"bridge mdb help\".\n", *argv);
+	exit(-1);
+}
diff --git a/iproute2/bridge/monitor.c b/iproute2/bridge/monitor.c
new file mode 100644
index 0000000..d8341ec
--- /dev/null
+++ b/iproute2/bridge/monitor.c
@@ -0,0 +1,144 @@
+/*
+ * brmonitor.c		"bridge monitor"
+ *
+ *		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.
+ *
+ * Authors:	Stephen Hemminger <shemminger@vyatta.com>
+ *
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <time.h>
+#include <sys/socket.h>
+#include <sys/time.h>
+#include <net/if.h>
+#include <netinet/in.h>
+#include <linux/if_bridge.h>
+#include <linux/neighbour.h>
+#include <string.h>
+
+#include "utils.h"
+#include "br_common.h"
+
+
+static void usage(void) __attribute__((noreturn));
+int prefix_banner;
+
+static void usage(void)
+{
+	fprintf(stderr, "Usage: bridge monitor [file | link | fdb | mdb | all]\n");
+	exit(-1);
+}
+
+static int accept_msg(const struct sockaddr_nl *who,
+		      struct rtnl_ctrl_data *ctrl,
+		      struct nlmsghdr *n, void *arg)
+{
+	FILE *fp = arg;
+
+	if (timestamp)
+		print_timestamp(fp);
+
+	switch (n->nlmsg_type) {
+	case RTM_NEWLINK:
+	case RTM_DELLINK:
+		if (prefix_banner)
+			fprintf(fp, "[LINK]");
+
+		return print_linkinfo(who, n, arg);
+
+	case RTM_NEWNEIGH:
+	case RTM_DELNEIGH:
+		if (prefix_banner)
+			fprintf(fp, "[NEIGH]");
+		return print_fdb(who, n, arg);
+
+	case RTM_NEWMDB:
+	case RTM_DELMDB:
+		if (prefix_banner)
+			fprintf(fp, "[MDB]");
+		return print_mdb(who, n, arg);
+
+	case NLMSG_TSTAMP:
+		print_nlmsg_timestamp(fp, n);
+		return 0;
+
+	default:
+		return 0;
+	}
+}
+
+int do_monitor(int argc, char **argv)
+{
+	char *file = NULL;
+	unsigned groups = ~RTMGRP_TC;
+	int llink=0;
+	int lneigh=0;
+	int lmdb=0;
+
+	rtnl_close(&rth);
+
+	while (argc > 0) {
+		if (matches(*argv, "file") == 0) {
+			NEXT_ARG();
+			file = *argv;
+		} else if (matches(*argv, "link") == 0) {
+			llink=1;
+			groups = 0;
+		} else if (matches(*argv, "fdb") == 0) {
+			lneigh = 1;
+			groups = 0;
+		} else if (matches(*argv, "mdb") == 0) {
+			lmdb = 1;
+			groups = 0;
+		} else if (strcmp(*argv, "all") == 0) {
+			groups = ~RTMGRP_TC;
+			prefix_banner=1;
+		} else if (matches(*argv, "help") == 0) {
+			usage();
+		} else {
+			fprintf(stderr, "Argument \"%s\" is unknown, try \"bridge monitor help\".\n", *argv);
+			exit(-1);
+		}
+		argc--;	argv++;
+	}
+
+	if (llink)
+		groups |= nl_mgrp(RTNLGRP_LINK);
+
+	if (lneigh) {
+		groups |= nl_mgrp(RTNLGRP_NEIGH);
+	}
+
+	if (lmdb) {
+		groups |= nl_mgrp(RTNLGRP_MDB);
+	}
+
+	if (file) {
+		FILE *fp;
+		int err;
+		fp = fopen(file, "r");
+		if (fp == NULL) {
+			perror("Cannot fopen");
+			exit(-1);
+		}
+		err = rtnl_from_file(fp, accept_msg, stdout);
+		fclose(fp);
+		return err;
+	}
+
+	if (rtnl_open(&rth, groups) < 0)
+		exit(1);
+	ll_init_map(&rth);
+
+	if (rtnl_listen(&rth, accept_msg, stdout) < 0)
+		exit(2);
+
+	return 0;
+}
+
diff --git a/iproute2/bridge/vlan.c b/iproute2/bridge/vlan.c
new file mode 100644
index 0000000..ac2f523
--- /dev/null
+++ b/iproute2/bridge/vlan.c
@@ -0,0 +1,263 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <sys/socket.h>
+#include <net/if.h>
+#include <netinet/in.h>
+#include <linux/if_bridge.h>
+#include <linux/if_ether.h>
+#include <string.h>
+
+#include "libnetlink.h"
+#include "br_common.h"
+#include "utils.h"
+
+static unsigned int filter_index;
+
+static void usage(void)
+{
+	fprintf(stderr, "Usage: bridge vlan { add | del } vid VLAN_ID dev DEV [ pvid] [ untagged ]\n");
+	fprintf(stderr, "                                                     [ self ] [ master ]\n");
+	fprintf(stderr, "       bridge vlan { show } [ dev DEV ]\n");
+	exit(-1);
+}
+
+static int vlan_modify(int cmd, int argc, char **argv)
+{
+	struct {
+		struct nlmsghdr 	n;
+		struct ifinfomsg 	ifm;
+		char   			buf[1024];
+	} req;
+	char *d = NULL;
+	short vid = -1;
+	short vid_end = -1;
+	struct rtattr *afspec;
+	struct bridge_vlan_info vinfo;
+	unsigned short flags = 0;
+
+	memset(&vinfo, 0, sizeof(vinfo));
+	memset(&req, 0, sizeof(req));
+
+	req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg));
+	req.n.nlmsg_flags = NLM_F_REQUEST;
+	req.n.nlmsg_type = cmd;
+	req.ifm.ifi_family = PF_BRIDGE;
+
+	while (argc > 0) {
+		if (strcmp(*argv, "dev") == 0) {
+			NEXT_ARG();
+			d = *argv;
+		} else if (strcmp(*argv, "vid") == 0) {
+			char *p;
+			NEXT_ARG();
+			p = strchr(*argv, '-');
+			if (p) {
+				*p = '\0';
+				p++;
+				vid = atoi(*argv);
+				vid_end = atoi(p);
+				vinfo.flags |= BRIDGE_VLAN_INFO_RANGE_BEGIN;
+			} else {
+				vid = atoi(*argv);
+			}
+		} else if (strcmp(*argv, "self") == 0) {
+			flags |= BRIDGE_FLAGS_SELF;
+		} else if (strcmp(*argv, "master") == 0) {
+			flags |= BRIDGE_FLAGS_MASTER;
+		} else if (strcmp(*argv, "pvid") == 0) {
+			vinfo.flags |= BRIDGE_VLAN_INFO_PVID;
+		} else if (strcmp(*argv, "untagged") == 0) {
+			vinfo.flags |= BRIDGE_VLAN_INFO_UNTAGGED;
+		} else {
+			if (matches(*argv, "help") == 0) {
+				NEXT_ARG();
+			}
+		}
+		argc--; argv++;
+	}
+
+	if (d == NULL || vid == -1) {
+		fprintf(stderr, "Device and VLAN ID are required arguments.\n");
+		return -1;
+	}
+
+	req.ifm.ifi_index = ll_name_to_index(d);
+	if (req.ifm.ifi_index == 0) {
+		fprintf(stderr, "Cannot find bridge device \"%s\"\n", d);
+		return -1;
+	}
+
+	if (vid >= 4096) {
+		fprintf(stderr, "Invalid VLAN ID \"%hu\"\n", vid);
+		return -1;
+	}
+
+	if (vinfo.flags & BRIDGE_VLAN_INFO_RANGE_BEGIN) {
+		if (vid_end == -1 || vid_end >= 4096 || vid >= vid_end) {
+			fprintf(stderr, "Invalid VLAN range \"%hu-%hu\"\n",
+				vid, vid_end);
+			return -1;
+		}
+		if (vinfo.flags & BRIDGE_VLAN_INFO_PVID) {
+			fprintf(stderr,
+				"pvid cannot be configured for a vlan range\n");
+			return -1;
+		}
+	}
+
+	afspec = addattr_nest(&req.n, sizeof(req), IFLA_AF_SPEC);
+
+	if (flags)
+		addattr16(&req.n, sizeof(req), IFLA_BRIDGE_FLAGS, flags);
+
+	vinfo.vid = vid;
+	if (vid_end != -1) {
+		/* send vlan range start */
+		addattr_l(&req.n, sizeof(req), IFLA_BRIDGE_VLAN_INFO, &vinfo,
+			  sizeof(vinfo));
+		vinfo.flags &= ~BRIDGE_VLAN_INFO_RANGE_BEGIN;
+
+		/* Now send the vlan range end */
+		vinfo.flags |= BRIDGE_VLAN_INFO_RANGE_END;
+		vinfo.vid = vid_end;
+		addattr_l(&req.n, sizeof(req), IFLA_BRIDGE_VLAN_INFO, &vinfo,
+			  sizeof(vinfo));
+	} else {
+		addattr_l(&req.n, sizeof(req), IFLA_BRIDGE_VLAN_INFO, &vinfo,
+			  sizeof(vinfo));
+	}
+
+	addattr_nest_end(&req.n, afspec);
+
+	if (rtnl_talk(&rth, &req.n, NULL, 0) < 0)
+		return -1;
+
+	return 0;
+}
+
+static int print_vlan(const struct sockaddr_nl *who,
+		      struct nlmsghdr *n,
+		      void *arg)
+{
+	FILE *fp = arg;
+	struct ifinfomsg *ifm = NLMSG_DATA(n);
+	int len = n->nlmsg_len;
+	struct rtattr * tb[IFLA_MAX+1];
+
+	if (n->nlmsg_type != RTM_NEWLINK) {
+		fprintf(stderr, "Not RTM_NEWLINK: %08x %08x %08x\n",
+			n->nlmsg_len, n->nlmsg_type, n->nlmsg_flags);
+		return 0;
+	}
+
+	len -= NLMSG_LENGTH(sizeof(*ifm));
+	if (len < 0) {
+		fprintf(stderr, "BUG: wrong nlmsg len %d\n", len);
+		return -1;
+	}
+
+	if (ifm->ifi_family != AF_BRIDGE)
+		return 0;
+
+	if (filter_index && filter_index != ifm->ifi_index)
+		return 0;
+
+	parse_rtattr(tb, IFLA_MAX, IFLA_RTA(ifm), len);
+
+	/* if AF_SPEC isn't there, vlan table is not preset for this port */
+	if (!tb[IFLA_AF_SPEC]) {
+		fprintf(fp, "%s\tNone\n", ll_index_to_name(ifm->ifi_index));
+		return 0;
+	} else {
+		struct rtattr *i, *list = tb[IFLA_AF_SPEC];
+		int rem = RTA_PAYLOAD(list);
+
+		fprintf(fp, "%s", ll_index_to_name(ifm->ifi_index));
+		for (i = RTA_DATA(list); RTA_OK(i, rem); i = RTA_NEXT(i, rem)) {
+			struct bridge_vlan_info *vinfo;
+
+			if (i->rta_type != IFLA_BRIDGE_VLAN_INFO)
+				continue;
+
+			vinfo = RTA_DATA(i);
+			if (vinfo->flags & BRIDGE_VLAN_INFO_RANGE_END)
+				fprintf(fp, "-%hu", vinfo->vid);
+			else
+				fprintf(fp, "\t %hu", vinfo->vid);
+			if (vinfo->flags & BRIDGE_VLAN_INFO_RANGE_BEGIN)
+				continue;
+			if (vinfo->flags & BRIDGE_VLAN_INFO_PVID)
+				fprintf(fp, " PVID");
+			if (vinfo->flags & BRIDGE_VLAN_INFO_UNTAGGED)
+				fprintf(fp, " Egress Untagged");
+			fprintf(fp, "\n");
+		}
+	}
+	fprintf(fp, "\n");
+	fflush(fp);
+	return 0;
+}
+
+static int vlan_show(int argc, char **argv)
+{
+	char *filter_dev = NULL;
+
+	while (argc > 0) {
+		if (strcmp(*argv, "dev") == 0) {
+			NEXT_ARG();
+			if (filter_dev)
+				duparg("dev", *argv);
+			filter_dev = *argv;
+		}
+		argc--; argv++;
+	}
+
+	if (filter_dev) {
+		if ((filter_index = if_nametoindex(filter_dev)) == 0) {
+			fprintf(stderr, "Cannot find device \"%s\"\n",
+			       filter_dev);
+			return -1;
+		}
+	}
+
+	if (rtnl_wilddump_req_filter(&rth, PF_BRIDGE, RTM_GETLINK,
+				    (compress_vlans ?
+				    RTEXT_FILTER_BRVLAN_COMPRESSED :
+				    RTEXT_FILTER_BRVLAN)) < 0) {
+		perror("Cannont send dump request");
+		exit(1);
+	}
+
+	printf("port\tvlan ids\n");
+	if (rtnl_dump_filter(&rth, print_vlan, stdout) < 0) {
+		fprintf(stderr, "Dump ternminated\n");
+		exit(1);
+	}
+
+	return 0;
+}
+
+
+int do_vlan(int argc, char **argv)
+{
+	ll_init_map(&rth);
+
+	if (argc > 0) {
+		if (matches(*argv, "add") == 0)
+			return vlan_modify(RTM_SETLINK, argc-1, argv+1);
+		if (matches(*argv, "delete") == 0)
+			return vlan_modify(RTM_DELLINK, argc-1, argv+1);
+		if (matches(*argv, "show") == 0 ||
+		    matches(*argv, "lst") == 0 ||
+		    matches(*argv, "list") == 0)
+			return vlan_show(argc-1, argv+1);
+		if (matches(*argv, "help") == 0)
+			usage();
+	} else
+		return vlan_show(0, NULL);
+
+	fprintf(stderr, "Command \"%s\" is unknown, try \"bridge fdb help\".\n", *argv);
+	exit(-1);
+}
diff --git a/iproute2/configure b/iproute2/configure
new file mode 100755
index 0000000..d2540b0
--- /dev/null
+++ b/iproute2/configure
@@ -0,0 +1,359 @@
+#! /bin/bash
+# This is not an autoconf generated configure
+#
+INCLUDE=${1:-"$PWD/include"}
+
+# Make a temp directory in build tree.
+TMPDIR=$(mktemp -d config.XXXXXX)
+trap 'status=$?; rm -rf $TMPDIR; exit $status' EXIT HUP INT QUIT TERM
+
+check_prog()
+{
+    echo -n "$2"
+    command -v $1 >/dev/null 2>&1 && (echo "$3:=y" >> Config; echo "yes") || (echo "no"; return 1)
+}
+
+check_docs()
+{
+    if check_prog latex " latex: " HAVE_LATEX; then
+        check_prog pdflatex " pdflatex: " HAVE_PDFLATEX || echo " WARNING: no PDF docs can be built from LaTeX files"
+        check_prog sgml2latex " sgml2latex: " HAVE_SGML2LATEX || echo " WARNING: no LaTeX files can be build from SGML files"
+    else
+        echo " WARNING: no docs can be built from LaTeX files"
+    fi
+
+    check_prog sgml2html " sgml2html: " HAVE_SGML2HTML || echo " WARNING: no HTML docs can be built from SGML"
+}
+
+check_toolchain()
+{
+    : ${PKG_CONFIG:=pkg-config}
+    : ${AR=ar}
+    : ${CC=gcc}
+    echo "PKG_CONFIG:=${PKG_CONFIG}" >>Config
+    echo "AR:=${AR}" >>Config
+    echo "CC:=${CC}" >>Config
+}
+
+check_atm()
+{
+    cat >$TMPDIR/atmtest.c <<EOF
+#include <atm.h>
+int main(int argc, char **argv) {
+	struct atm_qos qos;
+	(void) text2qos("aal5,ubr:sdu=9180,rx:none",&qos,0);
+	return 0;
+}
+EOF
+
+    $CC -I$INCLUDE -o $TMPDIR/atmtest $TMPDIR/atmtest.c -latm >/dev/null 2>&1
+    if [ $? -eq 0 ]
+    then
+	echo "TC_CONFIG_ATM:=y" >>Config
+	echo yes
+    else
+	echo no
+    fi
+    rm -f $TMPDIR/atmtest.c $TMPDIR/atmtest
+}
+
+check_xt()
+{
+    #check if we have xtables from iptables >= 1.4.5.
+    cat >$TMPDIR/ipttest.c <<EOF
+#include <xtables.h>
+#include <linux/netfilter.h>
+static struct xtables_globals test_globals = {
+	.option_offset = 0,
+	.program_name = "tc-ipt",
+	.program_version = XTABLES_VERSION,
+	.orig_opts = NULL,
+	.opts = NULL,
+	.exit_err = NULL,
+};
+
+int main(int argc, char **argv)
+{
+	xtables_init_all(&test_globals, NFPROTO_IPV4);
+	return 0;
+}
+EOF
+
+    if $CC -I$INCLUDE $IPTC -o $TMPDIR/ipttest $TMPDIR/ipttest.c $IPTL \
+	$(${PKG_CONFIG} xtables --cflags --libs) -ldl >/dev/null 2>&1
+    then
+	echo "TC_CONFIG_XT:=y" >>Config
+	echo "using xtables"
+    fi
+    rm -f $TMPDIR/ipttest.c $TMPDIR/ipttest
+}
+
+check_xt_old()
+{
+    # bail if previous XT checks has already succeded.
+    if grep -q TC_CONFIG_XT Config
+    then
+	return
+    fi
+
+    #check if we dont need our internal header ..
+    cat >$TMPDIR/ipttest.c <<EOF
+#include <xtables.h>
+char *lib_dir;
+unsigned int global_option_offset = 0;
+const char *program_version = XTABLES_VERSION;
+const char *program_name = "tc-ipt";
+struct afinfo afinfo = {
+	.libprefix      = "libxt_",
+};
+
+void exit_error(enum exittype status, const char *msg, ...)
+{
+}
+
+int main(int argc, char **argv) {
+
+	return 0;
+}
+
+EOF
+
+    $CC -I$INCLUDE $IPTC -o $TMPDIR/ipttest $TMPDIR/ipttest.c $IPTL -ldl >/dev/null 2>&1
+    if [ $? -eq 0 ]
+    then
+	echo "TC_CONFIG_XT_OLD:=y" >>Config
+	echo "using old xtables (no need for xt-internal.h)"
+    fi
+    rm -f $TMPDIR/ipttest.c $TMPDIR/ipttest
+}
+
+check_xt_old_internal_h()
+{
+    # bail if previous XT checks has already succeded.
+    if grep -q TC_CONFIG_XT Config
+    then
+	return
+    fi
+
+    #check if we need our own internal.h
+    cat >$TMPDIR/ipttest.c <<EOF
+#include <xtables.h>
+#include "xt-internal.h"
+char *lib_dir;
+unsigned int global_option_offset = 0;
+const char *program_version = XTABLES_VERSION;
+const char *program_name = "tc-ipt";
+struct afinfo afinfo = {
+	.libprefix      = "libxt_",
+};
+
+void exit_error(enum exittype status, const char *msg, ...)
+{
+}
+
+int main(int argc, char **argv) {
+
+	return 0;
+}
+
+EOF
+	$CC -I$INCLUDE $IPTC -o $TMPDIR/ipttest $TMPDIR/ipttest.c $IPTL -ldl >/dev/null 2>&1
+
+	if [ $? -eq 0 ]
+	then
+	    echo "using old xtables with xt-internal.h"
+	    echo "TC_CONFIG_XT_OLD_H:=y" >>Config
+	fi
+	rm -f $TMPDIR/ipttest.c $TMPDIR/ipttest
+}
+
+check_ipt()
+{
+	if ! grep TC_CONFIG_XT Config > /dev/null
+	then
+		echo "using iptables"
+	fi
+}
+
+check_ipt_lib_dir()
+{
+	IPT_LIB_DIR=$(${PKG_CONFIG} --variable=xtlibdir xtables)
+	if [ -n "$IPT_LIB_DIR" ]; then
+		echo $IPT_LIB_DIR
+		echo "IPT_LIB_DIR:=$IPT_LIB_DIR" >> Config
+		return
+	fi
+
+	for dir in /lib /usr/lib /usr/local/lib
+	do
+		for file in $dir/{xtables,iptables}/lib*t_*so ; do
+			if [ -f $file ]; then
+				echo ${file%/*}
+				echo "IPT_LIB_DIR:=${file%/*}" >> Config
+				return
+			fi
+		done
+	done
+	echo "not found!"
+}
+
+check_setns()
+{
+    cat >$TMPDIR/setnstest.c <<EOF
+#include <sched.h>
+int main(int argc, char **argv)
+{
+	(void)setns(0,0);
+	return 0;
+}
+EOF
+    $CC -I$INCLUDE -o $TMPDIR/setnstest $TMPDIR/setnstest.c >/dev/null 2>&1
+    if [ $? -eq 0 ]
+    then
+	echo "IP_CONFIG_SETNS:=y" >>Config
+	echo "yes"
+    else
+	echo "no"
+    fi
+    rm -f $TMPDIR/setnstest.c $TMPDIR/setnstest
+}
+
+check_ipset()
+{
+    cat >$TMPDIR/ipsettest.c <<EOF
+#include <linux/netfilter/ipset/ip_set.h>
+#ifndef IP_SET_INVALID
+#define IPSET_DIM_MAX 3
+typedef unsigned short ip_set_id_t;
+#endif
+#include <linux/netfilter/xt_set.h>
+
+struct xt_set_info info;
+#if IPSET_PROTOCOL == 6
+int main(void)
+{
+	return IPSET_MAXNAMELEN;
+}
+#else
+#error unknown ipset version
+#endif
+EOF
+
+    if $CC -I$INCLUDE -o $TMPDIR/ipsettest $TMPDIR/ipsettest.c >/dev/null 2>&1
+    then
+	echo "TC_CONFIG_IPSET:=y" >>Config
+	echo "yes"
+    else
+	echo "no"
+    fi
+    rm -f $TMPDIR/ipsettest.c $TMPDIR/ipsettest
+}
+
+check_elf()
+{
+    cat >$TMPDIR/elftest.c <<EOF
+#include <libelf.h>
+#include <gelf.h>
+int main(void)
+{
+	Elf_Scn *scn;
+	GElf_Shdr shdr;
+	return elf_version(EV_CURRENT);
+}
+EOF
+
+    if $CC -I$INCLUDE -o $TMPDIR/elftest $TMPDIR/elftest.c -lelf >/dev/null 2>&1
+    then
+	echo "TC_CONFIG_ELF:=y" >>Config
+	echo "yes"
+    else
+	echo "no"
+    fi
+    rm -f $TMPDIR/elftest.c $TMPDIR/elftest
+}
+
+check_selinux()
+# SELinux is a compile time option in the ss utility
+{
+	if ${PKG_CONFIG} libselinux --exists
+	then
+		echo "HAVE_SELINUX:=y" >>Config
+		echo "yes"
+	else
+		echo "no"
+	fi
+}
+
+check_mnl()
+{
+	if ${PKG_CONFIG} libmnl --exists
+	then
+		echo "HAVE_MNL:=y" >>Config
+		echo "yes"
+	else
+		echo "no"
+	fi
+}
+
+check_berkeley_db()
+{
+    cat >$TMPDIR/dbtest.c <<EOF
+#include <fcntl.h>
+#include <stdlib.h>
+#include <db_185.h>
+int main(int argc, char **argv) {
+	dbopen("/tmp/xxx_test_db.db", O_CREAT|O_RDWR, 0644, DB_HASH, NULL);
+	return 0;
+}
+EOF
+    $CC -I$INCLUDE -o $TMPDIR/dbtest $TMPDIR/dbtest.c -ldb >/dev/null 2>&1
+    if [ $? -eq 0 ]
+    then
+	echo "HAVE_BERKELEY_DB:=y" >>Config
+	echo "yes"
+    else
+	echo "no"
+    fi
+    rm -f $TMPDIR/dbtest.c $TMPDIR/dbtest
+}
+
+echo "# Generated config based on" $INCLUDE >Config
+check_toolchain
+
+echo "TC schedulers"
+
+echo -n " ATM	"
+check_atm
+
+echo -n " IPT	"
+check_xt
+check_xt_old
+check_xt_old_internal_h
+check_ipt
+
+echo -n " IPSET  "
+check_ipset
+
+echo
+echo -n "iptables modules directory: "
+check_ipt_lib_dir
+
+echo -n "libc has setns: "
+check_setns
+
+echo -n "SELinux support: "
+check_selinux
+
+echo -n "ELF support: "
+check_elf
+
+echo -n "libmnl support: "
+check_mnl
+
+echo -n "Berkeley DB: "
+check_berkeley_db
+
+echo
+echo -n "docs:"
+check_docs
+echo
diff --git a/iproute2/doc/Makefile b/iproute2/doc/Makefile
new file mode 100644
index 0000000..e9c0ff7
--- /dev/null
+++ b/iproute2/doc/Makefile
@@ -0,0 +1,73 @@
+PSFILES=ip-cref.ps ip-tunnels.ps api-ip6-flowlabels.ps ss.ps nstat.ps arpd.ps rtstat.ps
+# tc-cref.ps
+# api-rtnl.tex api-pmtudisc.tex api-news.tex
+# iki-netdev.ps iki-neighdst.ps
+
+
+LATEX=latex
+DVIPS=dvips
+SGML2DVI=sgml2latex
+SGML2HTML=sgml2html -s 0
+LPR=lpr -Zsduplex
+SHELL=bash
+PAGESIZE=a4
+PAGESPERPAGE=2
+
+HTMLFILES=$(subst .sgml,.html,$(shell echo *.sgml))
+DVIFILES=$(subst .ps,.dvi,$(PSFILES))
+PDFFILES=$(subst .ps,.pdf,$(PSFILES))
+
+
+all: pstwocol
+
+pstwocol: $(PSFILES)
+
+html: $(HTMLFILES)
+
+dvi: $(DVIFILES)
+
+pdf: $(PDFFILES)
+
+print: $(PSFILES)
+	$(LPR) $(PSFILES)
+
+%.tex: %.sgml
+	$(SGML2DVI) --output=tex $<
+
+%.dvi: %.sgml
+	$(SGML2DVI) --output=dvi $<
+
+%.dvi: %.tex
+	@set -e; pass=2; echo "Running LaTeX $<"; \
+	while [ `$(LATEX) $< </dev/null 2>&1 | \
+		 grep -c '^\(LaTeX Warning: Label(s) may\|No file \|! Emergency stop\)'` -ge 1 ]; do \
+		if [ $$pass -gt 3 ]; then \
+			echo "Seems, something is wrong. Try by hands." ; exit 1 ; \
+		fi; \
+		echo "Re-running LaTeX $<, $${pass}d pass"; pass=$$[$$pass + 1]; \
+	done
+
+%.pdf: %.tex
+	@set -e; pass=2; echo "Running pdfLaTeX $<"; \
+	while [ `pdflatex $< </dev/null 2>&1 | \
+		 grep -c '^\(LaTeX Warning: Label(s) may\|No file \|! Emergency stop\)'` -ge 1 ]; do \
+		if [ $$pass -gt 3 ]; then \
+			echo "Seems, something is wrong. Try by hands." ; exit 1 ; \
+		fi; \
+		echo "Re-running pdfLaTeX $<, $${pass}d pass"; pass=$$[$$pass + 1]; \
+	done
+#%.pdf: %.ps
+#	ps2pdf $<
+
+%.ps: %.dvi
+	$(DVIPS) $< -o $@
+
+%.html: %.sgml
+	$(SGML2HTML) $<
+
+install:
+	install -m 0644 $(shell echo *.tex) $(DESTDIR)$(DOCDIR)
+	install -m 0644 $(shell echo *.sgml) $(DESTDIR)$(DOCDIR)
+
+clean:
+	rm -f *.aux *.log *.toc $(PSFILES) $(DVIFILES) *.html *.pdf
diff --git a/iproute2/doc/Plan b/iproute2/doc/Plan
new file mode 100644
index 0000000..55f478e
--- /dev/null
+++ b/iproute2/doc/Plan
@@ -0,0 +1,16 @@
+Partially finished work.
+
+1.  User Reference manuals.
+1.1 IP Command reference (ip-cref.tex, published)
+1.2 TC Command reference (tc-cref.tex)
+1.3 IP tunnels (ip-tunnels.tex, published)
+
+2.  Linux-2.2 Networking API
+2.1 RTNETLINK (api-rtnl.tex)
+2.2 Path MTU Discovery (api-pmtudisc.tex)
+2.3 IPv6 Flow Labels (api-ip6-flowlabels.tex, published)
+2.4 Miscellaneous extensions (api-misc.tex)
+
+3.  Linux-2.2 Networking Intra-Kernel Interfaces
+3.1 NetDev --- Networking Devices and netdev... (iki-netdev.tex)
+3.2 Neighbour cache and destination cache. (iki-neighdst.tex)
diff --git a/iproute2/doc/SNAPSHOT.tex b/iproute2/doc/SNAPSHOT.tex
new file mode 100644
index 0000000..7ed0298
--- /dev/null
+++ b/iproute2/doc/SNAPSHOT.tex
@@ -0,0 +1 @@
+\def\Draft{020116}
diff --git a/iproute2/doc/actions/actions-general b/iproute2/doc/actions/actions-general
new file mode 100644
index 0000000..70f7cd6
--- /dev/null
+++ b/iproute2/doc/actions/actions-general
@@ -0,0 +1,257 @@
+
+This documented is slightly dated but should give you idea of how things
+work.
+
+What is it?
+-----------
+
+An extension to the filtering/classification architecture of Linux Traffic
+Control. 
+Up to 2.6.8 the only action that could be "attached" to a filter was policing. 
+i.e you could say something like:
+
+-----
+tc filter add dev lo parent ffff: protocol ip prio 10 u32 match ip src \
+127.0.0.1/32 flowid 1:1 police mtu 4000 rate 1500kbit burst 90k
+-----
+
+which implies "if a packet is seen on the ingress of the lo device with
+a source IP address of 127.0.0.1/32 we give it a classification id  of 1:1 and
+we execute a policing action which rate limits its bandwidth utilization 
+to 1.5Mbps".
+
+The new extensions allow for more than just policing actions to be added.
+They are also fully backward compatible. If you have a kernel that doesnt
+understand them, then the effect is null i.e if you have a newer tc
+but older kernel, the actions are not installed. Likewise if you
+have a newer kernel but older tc, obviously the tc will use current
+syntax which will work fine. Of course to get the required effect you need
+both newer tc and kernel. If you are reading this you have the
+right tc ;->
+
+A side effect is that we can now get stateless firewalling to work with tc. 
+Essentially this is now an alternative to iptables.
+I wont go into details of my dislike for iptables at times, but 
+scalability is one of the main issues; however, if you need stateful
+classification - use netfilter (for now).
+
+This stuff works on both ingress and egress qdiscs.
+
+Features
+--------
+
+1) new additional syntax and actions enabled. Note old syntax is still valid.
+
+Essentially this is still the same syntax as tc with a new construct
+"action". The syntax is of the form:
+tc filter add <DEVICE> parent 1:0 protocol ip prio 10 <Filter description>
+flowid 1:1 action <ACTION description>*
+
+You can have as many actions as you want (within sensible reasoning).
+
+In the past the only real action was the policer; i.e you could do something
+along the lines of:
+tc filter add dev lo parent ffff: protocol ip prio 10 u32 \
+match ip src 127.0.0.1/32 flowid 1:1 \
+police mtu 4000 rate 1500kbit burst 90k
+
+Although you can still use the same syntax, now you can say:
+
+tc filter add dev lo parent 1:0 protocol ip prio 10 u32 \
+match ip src 127.0.0.1/32 flowid 1:1 \
+action police mtu 4000 rate 1500kbit burst 90k
+
+" generic Actions" (gact) at the moment are: 
+{ drop, pass, reclassify, continue}
+(If you have others, no listed here give me a reason and we will add them)
++drop says to drop the packet
++pass and ok (are equivalent) says to accept it
++reclassify requests for reclassification of the packet
++continue requests for next lookup to match
+
+2)In order to take advantage of some of the targets written by the
+iptables people, a classifier can have a packet being massaged by an
+iptable target. I have only tested with mangler targets up to now.
+(infact anything that is not in the mangling table is disabled right now)
+
+In terms of hooks:
+*ingress is mapped to pre-routing hook
+*egress is mapped to post-routing hook
+I dont see much value in the other hooks, if you see it and email me good
+reasons, the addition is trivial.
+
+Example syntax for iptables targets usage becomes:
+tc filter add ..... u32 <u32 syntax> action ipt -j <iptables target syntax>
+
+example:
+tc filter add dev lo parent ffff: protocol ip prio 8 u32 \
+match ip dst 127.0.0.8/32 flowid 1:12 \
+action ipt -j mark --set-mark 2
+
+NOTE: flowid 1:12 is parsed flowid 0x1:0x12.  Make sure if you want flowid
+decimal 12, then use flowid 1:c.
+
+3) A feature i call pipe
+The motivation is derived from Unix pipe mechanism but applied to packets.
+Essentially take a matching packet and pass it through 
+action1 | action2 | action3 etc.
+You could do something similar to this with the tc policer and the "continue"
+operator but this rather restricts it to just the policer and requires 
+multiple rules (and lookups, hence quiet inefficient); 
+
+as an example -- and please note that this is just an example _not_ The 
+Word Youve Been Waiting For (yes i have had problems giving examples
+which ended becoming dogma in documents and people modifying them a little
+to look clever); 
+
+i selected the metering rates to be small so that i can show better how 
+things work.
+ 
+The script below does the following: 
+- an incoming packet from 10.0.0.21 is first given a firewall mark of 1. 
+
+- It is then metered to make sure it does not exceed its allocated rate of 
+1Kbps. If it doesnt exceed rate, this is where we terminate action execution.
+
+- If it does exceed its rate, its "color" changes to a mark of 2 and it is 
+then passed through a second meter.
+
+-The second meter is shared across all flows on that device [i am suprised 
+that this seems to be not a well know feature of the policer; Bert was telling 
+me that someone was writing a qdisc just to do sharing across multiple devices;
+it must be the summer heat again; weve had someone doing that every year around
+summer  -- the key to sharing is to use a operator "index" in your policer 
+rules (example "index 20"). All your rules have to use the same index to 
+share.]
+ 
+-If the second meter is exceeded the color of the flow changes further to 3.
+
+-We then pass the packet to another meter which is shared across all devices
+in the system. If this meter is exceeded we drop the packet.
+
+Note the mark can be used further up the system to do things like policy 
+or more interesting things on the egress.
+
+------------------ cut here -------------------------------
+#
+# Add an ingress qdisc on eth0
+tc qdisc add dev eth0 ingress
+#
+#if you see an incoming packet from 10.0.0.21
+tc filter add dev eth0 parent ffff: protocol ip prio 1 \
+u32 match ip src 10.0.0.21/32 flowid 1:15 \
+#
+# first give it a mark of 1
+action ipt -j mark --set-mark 1 index 2 \
+#
+# then pass it through a policer which allows 1kbps; if the flow
+# doesnt exceed that rate, this is where we stop, if it exceeds we
+# pipe the packet to the next action
+action police rate 1kbit burst 9k pipe \
+#
+# which marks the packet fwmark as 2 and pipes
+action ipt -j mark --set-mark 2 \
+#
+# next attempt to borrow b/width from a meter
+# used across all flows incoming on eth0("index 30")
+# and if that is exceeded we pipe to the next action
+action police index 30 mtu 5000 rate 1kbit burst 10k pipe \
+# mark it as fwmark 3 if exceeded
+action ipt -j mark --set-mark 3 \
+# and then attempt to borrow from a meter used by all devices in the
+# system. Should this be exceeded, drop the packet on the floor.
+action police index 20 mtu 5000 rate 1kbit burst 90k drop
+--------------------------------- 
+
+Now lets see the actions installed with 
+"tc filter show parent ffff: dev eth0"
+
+-------- output -----------
+jroot# tc filter show parent ffff: dev eth0
+filter protocol ip pref 1 u32 
+filter protocol ip pref 1 u32 fh 800: ht divisor 1 
+filter protocol ip pref 1 u32 fh 800::800 order 2048 key ht 800 bkt 0 flowid 1:15 
+
+   action order 1: tablename: mangle  hook: NF_IP_PRE_ROUTING 
+        target MARK set 0x1  index 2
+
+   action order 2: police 1 action pipe rate 1Kbit burst 9Kb mtu 2Kb 
+
+   action order 3: tablename: mangle  hook: NF_IP_PRE_ROUTING 
+        target MARK set 0x2  index 1
+
+   action order 4: police 30 action pipe rate 1Kbit burst 10Kb mtu 5000b 
+
+   action order 5: tablename: mangle  hook: NF_IP_PRE_ROUTING 
+        target MARK set 0x3  index 3
+
+   action order 6: police 20 action drop rate 1Kbit burst 90Kb mtu 5000b 
+
+  match 0a000015/ffffffff at 12
+-------------------------------
+
+Note the ordering of the actions is based on the order in which we entered
+them. In the future i will add explicit priorities.
+
+Now lets run a ping -f from 10.0.0.21 to this host; stop the ping after
+you see a few lines of dots
+
+----
+[root@jzny hadi]# ping -f  10.0.0.22
+PING 10.0.0.22 (10.0.0.22): 56 data bytes
+....................................................................................................................................................................................................................................................................................................................................................................................................................................................
+--- 10.0.0.22 ping statistics ---
+2248 packets transmitted, 1811 packets received, 19% packet loss
+round-trip min/avg/max = 0.7/9.3/20.1 ms
+-----------------------------
+
+Now lets take a look at the stats with "tc -s filter show parent ffff: dev eth0"
+
+--------------
+jroot# tc -s filter show parent ffff: dev eth0
+filter protocol ip pref 1 u32 
+filter protocol ip pref 1 u32 fh 800: ht divisor 1 
+filter protocol ip pref 1 u32 fh 800::800 order 2048 key ht 800 bkt 0 flowid 1:1
+5 
+
+   action order 1: tablename: mangle  hook: NF_IP_PRE_ROUTING 
+        target MARK set 0x1  index 2
+         Sent 188832 bytes 2248 pkts (dropped 0, overlimits 0) 
+
+   action order 2: police 1 action pipe rate 1Kbit burst 9Kb mtu 2Kb 
+         Sent 188832 bytes 2248 pkts (dropped 0, overlimits 2122) 
+
+   action order 3: tablename: mangle  hook: NF_IP_PRE_ROUTING 
+        target MARK set 0x2  index 1
+         Sent 178248 bytes 2122 pkts (dropped 0, overlimits 0) 
+
+   action order 4: police 30 action pipe rate 1Kbit burst 10Kb mtu 5000b 
+         Sent 178248 bytes 2122 pkts (dropped 0, overlimits 1945) 
+
+   action order 5: tablename: mangle  hook: NF_IP_PRE_ROUTING 
+        target MARK set 0x3  index 3
+         Sent 163380 bytes 1945 pkts (dropped 0, overlimits 0) 
+
+   action order 6: police 20 action drop rate 1Kbit burst 90Kb mtu 5000b 
+         Sent 163380 bytes 1945 pkts (dropped 0, overlimits 437) 
+
+  match 0a000015/ffffffff at 12
+-------------------------------
+
+Neat, eh?
+
+
+Wanna write an action module?
+------------------------------
+Its easy. Either look at the code or send me email. I will document at
+some point; will also accept documentation.
+
+TODO
+----
+
+Lotsa goodies/features coming. Requests also being accepted.
+At the moment the focus has been on getting the architecture in place.
+Expect new things in the spurious time i have to work on this
+(particularly around end of year when i have typically get time off
+from work).
+
diff --git a/iproute2/doc/actions/gact-usage b/iproute2/doc/actions/gact-usage
new file mode 100644
index 0000000..de1308d
--- /dev/null
+++ b/iproute2/doc/actions/gact-usage
@@ -0,0 +1,79 @@
+
+gact <ACTION> [RAND] [INDEX]
+
+Where: 
+	ACTION := reclassify | drop | continue | pass | ok 
+	RAND := random <RANDTYPE> <ACTION> <VAL>
+	RANDTYPE := netrand | determ
+        VAL : = value not exceeding 10000
+        INDEX := index value used
+      
+ACTION semantics
+- pass and ok are equivalent to accept
+- continue allows to restart classification lookup
+- drop drops packets
+- reclassify implies continue classification where we left off
+
+randomization
+--------------
+
+At the moment there are only two algorithms. One is deterministic
+and the other uses internal kernel netrand.
+
+Examples:
+
+Rules can be installed on both ingress and egress - this shows ingress
+only
+
+tc qdisc add dev eth0 ingress
+
+# example 1
+tc filter add dev eth0 parent ffff: protocol ip prio 6 u32 match ip src \
+10.0.0.9/32 flowid 1:16 action drop
+
+ping -c 20 10.0.0.9
+
+--
+filter u32
+filter u32 fh 800: ht divisor 1
+filter u32 fh 800::800 order 2048 key ht 800 bkt 0 flowid 1:16  (rule hit 32 success 20)
+  match 0a000009/ffffffff at 12 (success 20 )
+        action order 1: gact action drop
+         random type none pass val 0
+         index 1 ref 1 bind 1 installed 59 sec used 35 sec
+         Sent 1680 bytes 20 pkts (dropped 20, overlimits 0 )
+ 
+----
+
+# example 2
+#allow 1 out 10 randomly using the netrand generator
+tc filter add dev eth0 parent ffff: protocol ip prio 6 u32 match ip src \
+10.0.0.9/32 flowid 1:16 action drop random netrand ok 10
+ 
+ping -c 20 10.0.0.9
+
+----
+filter protocol ip pref 6 u32 filter protocol ip pref 6 u32 fh 800: ht divisor 1filter protocol ip pref 6 u32 fh 800::800 order 2048 key ht 800 bkt 0 flowid 1:16  (rule hit 20 success 20)
+  match 0a000009/ffffffff at 12 (success 20 )
+        action order 1: gact action drop
+         random type netrand pass val 10
+         index 5 ref 1 bind 1 installed 49 sec used 25 sec
+         Sent 1680 bytes 20 pkts (dropped 16, overlimits 0 )
+                                                                                
+--------
+#alternative: deterministically accept every second packet
+tc filter add dev eth0 parent ffff: protocol ip prio 6 u32 match ip src \
+10.0.0.9/32 flowid 1:16 action drop random determ ok 2
+                                                                                
+ping -c 20 10.0.0.9
+                                                                                
+tc -s filter show parent ffff: dev eth0
+-----
+filter protocol ip pref 6 u32 filter protocol ip pref 6 u32 fh 800: ht divisor 1filter protocol ip pref 6 u32 fh 800::800 order 2048 key ht 800 bkt 0 flowid 1:16  (rule hit 20 success 20)
+  match 0a000009/ffffffff at 12 (success 20 )
+        action order 1: gact action drop
+         random type determ pass val 2
+         index 4 ref 1 bind 1 installed 118 sec used 82 sec
+         Sent 1680 bytes 20 pkts (dropped 10, overlimits 0 )
+-----
+
diff --git a/iproute2/doc/actions/ifb-README b/iproute2/doc/actions/ifb-README
new file mode 100644
index 0000000..3d01179
--- /dev/null
+++ b/iproute2/doc/actions/ifb-README
@@ -0,0 +1,125 @@
+
+IFB is intended to replace IMQ.
+Advantage over current IMQ; cleaner in particular in in SMP;
+with a _lot_ less code.
+
+Known IMQ/IFB USES
+------------------
+
+As far as i know the reasons listed below is why people use IMQ. 
+It would be nice to know of anything else that i missed.
+
+1) qdiscs/policies that are per device as opposed to system wide.
+IFB allows for sharing.
+
+2) Allows for queueing incoming traffic for shaping instead of
+dropping. I am not aware of any study that shows policing is 
+worse than shaping in achieving the end goal of rate control.
+I would be interested if anyone is experimenting.
+
+3) Very interesting use: if you are serving p2p you may wanna give 
+preference to your own localy originated traffic (when responses come back)
+vs someone using your system to do bittorent. So QoSing based on state
+comes in as the solution. What people did to achive this was stick
+the IMQ somewhere prelocal hook.
+I think this is a pretty neat feature to have in Linux in general.
+(i.e not just for IMQ).
+But i wont go back to putting netfilter hooks in the device to satisfy
+this.  I also dont think its worth it hacking ifb some more to be 
+aware of say L3 info and play ip rule tricks to achieve this.
+--> Instead the plan is to have a contrack related action. This action will
+selectively either query/create contrack state on incoming packets. 
+Packets could then be redirected to ifb based on what happens -> eg 
+on incoming packets; if we find they are of known state we could send to 
+a different queue than one which didnt have existing state. This
+all however is dependent on whatever rules the admin enters.
+
+At the moment this 3rd function does not exist yet. I have decided that
+instead of sitting on the patch for another year, to release it and then 
+if theres pressure i will add this feature.
+
+An example, to provide functionality that most people use IMQ for below:
+
+--------
+export TC="/sbin/tc"
+
+$TC qdisc add dev ifb0 root handle 1: prio 
+$TC qdisc add dev ifb0 parent 1:1 handle 10: sfq
+$TC qdisc add dev ifb0 parent 1:2 handle 20: tbf rate 20kbit buffer 1600 limit 3000
+$TC qdisc add dev ifb0 parent 1:3 handle 30: sfq                                
+$TC filter add dev ifb0 protocol ip pref 1 parent 1: handle 1 fw classid 1:1
+$TC filter add dev ifb0 protocol ip pref 2 parent 1: handle 2 fw classid 1:2
+
+ifconfig ifb0 up
+
+$TC qdisc add dev eth0 ingress
+
+# redirect all IP packets arriving in eth0 to ifb0 
+# use mark 1 --> puts them onto class 1:1
+$TC filter add dev eth0 parent ffff: protocol ip prio 10 u32 \
+match u32 0 0 flowid 1:1 \
+action ipt -j MARK --set-mark 1 \
+action mirred egress redirect dev ifb0
+
+--------
+
+
+Run A Little test:
+
+from another machine ping so that you have packets going into the box:
+-----
+[root@jzny action-tests]# ping 10.22
+PING 10.22 (10.0.0.22): 56 data bytes
+64 bytes from 10.0.0.22: icmp_seq=0 ttl=64 time=2.8 ms
+64 bytes from 10.0.0.22: icmp_seq=1 ttl=64 time=0.6 ms
+64 bytes from 10.0.0.22: icmp_seq=2 ttl=64 time=0.6 ms
+
+--- 10.22 ping statistics ---
+3 packets transmitted, 3 packets received, 0% packet loss
+round-trip min/avg/max = 0.6/1.3/2.8 ms
+[root@jzny action-tests]# 
+-----
+Now look at some stats:
+
+---
+[root@jmandrake]:~# $TC -s filter show parent ffff: dev eth0
+filter protocol ip pref 10 u32 
+filter protocol ip pref 10 u32 fh 800: ht divisor 1 
+filter protocol ip pref 10 u32 fh 800::800 order 2048 key ht 800 bkt 0 flowid 1:1 
+  match 00000000/00000000 at 0
+        action order 1: tablename: mangle  hook: NF_IP_PRE_ROUTING 
+        target MARK set 0x1  
+        index 1 ref 1 bind 1 installed 4195sec  used 27sec 
+         Sent 252 bytes 3 pkts (dropped 0, overlimits 0) 
+
+        action order 2: mirred (Egress Redirect to device ifb0) stolen
+        index 1 ref 1 bind 1 installed 165 sec used 27 sec
+         Sent 252 bytes 3 pkts (dropped 0, overlimits 0) 
+
+[root@jmandrake]:~# $TC -s qdisc
+qdisc sfq 30: dev ifb0 limit 128p quantum 1514b 
+ Sent 0 bytes 0 pkts (dropped 0, overlimits 0) 
+qdisc tbf 20: dev ifb0 rate 20Kbit burst 1575b lat 2147.5s 
+ Sent 210 bytes 3 pkts (dropped 0, overlimits 0) 
+qdisc sfq 10: dev ifb0 limit 128p quantum 1514b 
+ Sent 294 bytes 3 pkts (dropped 0, overlimits 0) 
+qdisc prio 1: dev ifb0 bands 3 priomap  1 2 2 2 1 2 0 0 1 1 1 1 1 1 1 1
+ Sent 504 bytes 6 pkts (dropped 0, overlimits 0) 
+qdisc ingress ffff: dev eth0 ---------------- 
+ Sent 308 bytes 5 pkts (dropped 0, overlimits 0) 
+
+[root@jmandrake]:~# ifconfig ifb0
+ifb0    Link encap:Ethernet  HWaddr 00:00:00:00:00:00  
+          inet6 addr: fe80::200:ff:fe00:0/64 Scope:Link
+          UP BROADCAST RUNNING NOARP  MTU:1500  Metric:1
+          RX packets:6 errors:0 dropped:3 overruns:0 frame:0
+          TX packets:3 errors:0 dropped:0 overruns:0 carrier:0
+          collisions:0 txqueuelen:32 
+          RX bytes:504 (504.0 b)  TX bytes:252 (252.0 b)
+-----
+
+You send it any packet not originating from the actions it will drop them.
+[In this case the three dropped packets were ipv6 ndisc].
+
+cheers,
+jamal
diff --git a/iproute2/doc/actions/mirred-usage b/iproute2/doc/actions/mirred-usage
new file mode 100644
index 0000000..2622c43
--- /dev/null
+++ b/iproute2/doc/actions/mirred-usage
@@ -0,0 +1,164 @@
+
+Very funky action. I do plan to add to a few more things to it
+This is the basic stuff. Idea borrowed from the way ethernet switches
+mirror and redirect packets. The main difference with say a vannila
+ethernet switch is that you can use u32 classifier to select a
+flow to be mirrored. High end switches typically can select based
+on more than just a port (eg a 5 tuple classifier). They may also be
+capable of redirecting.
+
+Usage: 
+
+mirred <DIRECTION> <ACTION> [index INDEX] <dev DEVICENAME> 
+where: 
+DIRECTION := <ingress | egress>
+ACTION := <mirror | redirect>
+INDEX is the specific policy instance id
+DEVICENAME is the devicename
+
+Direction:
+- Ingress is not supported at the moment. It will be in the
+future as well as mirror/redirecting to a socket. 
+
+Action:
+- Mirror takes a copy of the packet and sends it to specified
+dev ("port" in ethernet switch/bridging terminology)
+- redirect
+steals the packet and redirects to specified destination dev.
+
+What NOT to do if you dont want your machine to crash:
+------------------------------------------------------
+
+Do not create loops! 
+Loops are not hard to create in the egress qdiscs.
+
+Here are simple rules to follow if you dont want to get
+hurt:
+A) Do not have the same packet go to same netdevice twice
+in a single graph of policies. Your machine will just hang!
+This is design intent _not a bug_ to teach you some lessons. 
+
+In the future if there are easy ways to do this in the kernel
+without affecting other packets not interested in this feature
+I will add them. At the moment that is not clear.
+
+Some examples of bad things NOT to do:
+1) redirecting eth0 to eth0
+2) eth0->eth1-> eth0
+3) eth0->lo-> eth1-> eth0
+
+B) Do not redirect from one IFB device to another.
+Remember that IFB is a very specialized case of packet redirecting
+device. Instead of redirecting it puts packets at the exact spot
+on the stack it found them from.
+Redirecting from ifbX->ifbY will actually not crash your machine but your 
+packets will all be dropped (this is much simpler to detect
+and resolve and is only affecting users of ifb as opposed to the
+whole stack).
+
+In the case of A) the problem has to do with a recursive contention
+for the devices queue lock and in the second case for the transmit lock.
+
+Some examples:
+-------------
+
+1) Mirror all packets arriving on eth0 to be sent out on eth1.
+You may have a sniffer or some accounting box hooked up on eth1.
+ 
+---
+tc qdisc add dev eth0 ingress
+tc filter add dev eth0 parent ffff: protocol ip prio 10 u32 \
+match u32 0 0 flowid 1:2 action mirred egress mirror dev eth1
+---
+
+If you replace "mirror" with "redirect" then not a copy but rather
+the original packet is sent to eth1.
+
+2) Host A is hooked  up to us on eth0
+
+# redirect all packets arriving on ingress of lo to eth0
+---
+tc qdisc add dev lo ingress
+tc filter add dev lo parent ffff: protocol ip prio 10 u32 \
+match u32 0 0 flowid 1:2 action mirred egress redirect dev eth0
+---
+
+On host A start a tcpdump on interface connecting to us.
+
+on our host ping -c 2 127.0.0.1
+
+Ping would fail since all packets are heading out eth0
+tcpudmp on host A would show them
+
+if you substitute the redirect with mirror above as in:
+tc filter add dev lo parent ffff: protocol ip prio 10 u32 \
+match u32 0 0 flowid 1:2 action mirred egress mirror dev eth0
+
+Then you should see the packets on both host A and the local
+stack (i.e ping would work).
+
+3) Even more funky example:
+
+#
+#allow 1 out 10 packets on ingress of lo to randomly make it to the 
+# host A (Randomness uses the netrand generator)
+#
+---
+tc filter add dev lo parent ffff: protocol ip prio 10 u32 \
+match u32 0 0 flowid 1:2 \
+action drop random determ ok 10\
+action mirred egress mirror dev eth0
+---
+
+4)
+# for packets from 10.0.0.9 going out on eth0 (could be local 
+# IP or something # we are forwarding) - 
+# if exceeding a 100Kbps rate, then redirect to eth1 
+#
+
+---
+tc qdisc add dev eth0 handle 1:0 root prio
+tc filter add dev eth0 parent 1:0 protocol ip prio 6 u32 \
+match ip src 10.0.0.9/32 flowid 1:16 \
+action police rate 100kbit burst 90k ok \
+action mirred egress mirror dev eth1
+---
+
+A more interesting example is when you mirror flows to a dummy device
+so you could tcpdump them (dummy by defaults drops all packets it sees).
+This is a very useful debug feature.
+
+Lets say you are policing packets from alias 192.168.200.200/32
+you dont want those to exceed 100kbps going out.
+
+---
+tc qdisc add dev eth0 handle 1:0 root prio
+tc filter add dev eth0 parent 1: protocol ip prio 10 u32 \
+match ip src 192.168.200.200/32 flowid 1:2 \
+action police rate 100kbit burst 90k drop
+---
+
+If you run tcpdump on eth0 you will see all packets going out
+with src 192.168.200.200/32 dropped or not (since tcpdump shows
+all packets being egressed).
+Extend the rule a little to see only the packets making it out.
+
+---
+tc qdisc add dev eth0 handle 1:0 root prio
+tc filter add dev eth0 parent 1: protocol ip prio 10 u32 \
+match ip src 192.168.200.200/32 flowid 1:2 \
+action police rate 10kbit burst 90k drop \
+action mirred egress mirror dev dummy0
+---
+
+Now fire tcpdump on dummy0 to see only those packets ..
+tcpdump -n -i dummy0 -x -e -t
+
+Essentially a good debugging/logging interface (sort of like
+BSDs speacialized log device does without needing one).
+
+If you replace mirror with redirect, those packets will be
+blackholed and will never make it out. 
+
+cheers,
+jamal
diff --git a/iproute2/doc/api-ip6-flowlabels.tex b/iproute2/doc/api-ip6-flowlabels.tex
new file mode 100644
index 0000000..aa34e94
--- /dev/null
+++ b/iproute2/doc/api-ip6-flowlabels.tex
@@ -0,0 +1,429 @@
+\documentstyle[12pt,twoside]{article}
+\def\TITLE{IPv6 Flow Labels}
+\input preamble
+\begin{center}
+\Large\bf IPv6 Flow Labels in Linux-2.2.
+\end{center}
+
+
+\begin{center}
+{ \large Alexey~N.~Kuznetsov } \\
+\em Institute for Nuclear Research, Moscow \\
+\verb|kuznet@ms2.inr.ac.ru| \\
+\rm April 11, 1999
+\end{center}
+
+\vspace{5mm}
+
+\tableofcontents
+
+\section{Introduction.}
+
+Every IPv6 packet carries 28 bits of flow information. RFC2460 splits
+these bits to two fields: 8 bits of traffic class (or DS field, if you
+prefer this term) and 20 bits of flow label. Currently there exist
+no well-defined API to manage IPv6 flow information. In this document
+I describe an attempt to design the API for Linux-2.2 IPv6 stack.
+
+\vskip 1mm
+
+The API must solve the following tasks:
+
+\begin{enumerate}
+
+\item To allow user to set traffic class bits.
+
+\item To allow user to read traffic class bits of received packets.
+This feature is not so useful as the first one, however it will be
+necessary f.e.\ to implement ECN [RFC2481] for datagram oriented services
+or to implement receiver side of SRP or another end-to-end protocol
+using traffic class bits.
+
+\item To assign flow labels to packets sent by user.
+
+\item To get flow labels of received packets. I do not know
+any applications of this feature, but it is possible that receiver will
+want to use flow labels to distinguish sub-flows.
+
+\item To allocate flow labels in the way, compliant to RFC2460. Namely:
+
+\begin{itemize}
+\item
+Flow labels must be uniformly distributed (pseudo-)random numbers,
+so that any subset of 20 bits can be used as hash key.
+
+\item
+Flows with coinciding source address and flow label must have identical
+destination address and not-fragmentable extensions headers (i.e.\ 
+hop by hop options and all the headers up to and including routing header,
+if it is present.)
+
+\begin{NB}
+There is a hole in specs: some hop-by-hop options can be
+defined only on per-packet base (f.e.\  jumbo payload option).
+Essentially, it means that such options cannot present in packets
+with flow labels.
+\end{NB}
+\begin{NB}
+NB notes here and below reflect only my personal opinion,
+they should be read with smile or should not be read at all :-).
+\end{NB}
+
+
+\item
+Flow labels have finite lifetime and source is not allowed to reuse
+flow label for another flow within the maximal lifetime has expired,
+so that intermediate nodes will be able to invalidate flow state before
+the label is taken over by another flow.
+Flow state, including lifetime, is propagated along datagram path
+by some application specific methods
+(f.e.\ in RSVP PATH messages or in some hop-by-hop option).
+
+
+\end{itemize}
+
+\end{enumerate}
+
+\section{Sending/receiving flow information.}
+
+\paragraph{Discussion.}
+\addcontentsline{toc}{subsection}{Discussion}
+It was proposed (Where? I do not remember any explicit statement)
+to solve the first four tasks using
+\verb|sin6_flowinfo| field added to \verb|struct| \verb|sockaddr_in6|
+(see RFC2553).
+
+\begin{NB}
+	This method is difficult to consider as reasonable, because it
+	puts additional overhead to all the services, despite of only
+	very small subset of them (none, to be more exact) really use it.
+	It contradicts both to IETF spirit and the letter. Before RFC2553
+	one justification existed, IPv6 address alignment left 4 byte
+	hole in \verb|sockaddr_in6| in any case. Now it has no justification.
+\end{NB}
+
+We have two problems with this method. The first one is common for all OSes:
+if \verb|recvmsg()| initializes \verb|sin6_flowinfo| to flow info
+of received packet, we loose one very important property of BSD socket API,
+namely, we are not allowed to use received address for reply directly
+and have to mangle it, even if we are not interested in flowinfo subtleties.
+
+\begin{NB}
+	RFC2553 adds new requirement: to clear \verb|sin6_flowinfo|.
+	Certainly, it is not solution but rather attempt to force applications
+	to make unnecessary work. Well, as usually, one mistake in design
+	is followed by attempts	to patch the hole and more mistakes...
+\end{NB}
+
+Another problem is Linux specific. Historically Linux IPv6 did not
+initialize \verb|sin6_flowinfo| at all, so that, if kernel does not
+support flow labels, this field is not zero, but a random number.
+Some applications also did not take care about it. 
+
+\begin{NB}
+Following RFC2553 such applications can be considered as broken,
+but I still think that they are right: clearing all the address
+before filling known fields is robust but stupid solution.
+Useless wasting CPU cycles and
+memory bandwidth is not a good idea. Such patches are acceptable
+as temporary hacks, but not as standard of the future.
+\end{NB}
+
+
+\paragraph{Implementation.}
+\addcontentsline{toc}{subsection}{Implementation}
+By default Linux IPv6 does not read \verb|sin6_flowinfo| field
+assuming that common applications are not obliged to initialize it
+and are permitted to consider it as pure alignment padding.
+In order to tell kernel that application
+is aware of this field, it is necessary to set socket option
+\verb|IPV6_FLOWINFO_SEND|.
+
+\begin{verbatim}
+  int on = 1;
+  setsockopt(sock, SOL_IPV6, IPV6_FLOWINFO_SEND,
+             (void*)&on, sizeof(on));
+\end{verbatim}
+
+Linux kernel never fills \verb|sin6_flowinfo| field, when passing
+message to user space, though the kernels which support flow labels
+initialize it to zero. If user wants to get received flowinfo, he
+will set option \verb|IPV6_FLOWINFO| and after this he will receive
+flowinfo as ancillary data object of type \verb|IPV6_FLOWINFO|
+(cf.\ RFC2292).
+
+\begin{verbatim}
+  int on = 1;
+  setsockopt(sock, SOL_IPV6, IPV6_FLOWINFO, (void*)&on, sizeof(on));
+\end{verbatim}
+
+Flowinfo received and latched by a connected TCP socket also may be fetched
+with \verb|getsockopt()| \verb|IPV6_PKTOPTIONS| together with
+another optional information.
+
+Besides that, in the spirit of RFC2292 the option \verb|IPV6_FLOWINFO|
+may be used as alternative way to send flowinfo with \verb|sendmsg()| or
+to latch it with \verb|IPV6_PKTOPTIONS|.
+
+\paragraph{Note about IPv6 options and destination address.}
+\addcontentsline{toc}{subsection}{IPv6 options and destination address}
+If \verb|sin6_flowinfo| does contain not zero flow label,
+destination address in \verb|sin6_addr| and non-fragmentable
+extension headers are ignored. Instead, kernel uses the values
+cached at flow setup (see below). However, for connected sockets
+kernel prefers the values set at connection time.
+
+\paragraph{Example.}
+\addcontentsline{toc}{subsection}{Example}
+After setting socket option \verb|IPV6_FLOWINFO|
+flowlabel and DS field are received as ancillary data object
+of type \verb|IPV6_FLOWINFO| and level \verb|SOL_IPV6|.
+In the cases when it is convenient to use \verb|recvfrom(2)|,
+it is possible to replace library variant with your own one,
+sort of:
+
+\begin{verbatim}
+#include <sys/socket.h>
+#include <netinet/in6.h>
+
+size_t recvfrom(int fd, char *buf, size_t len, int flags,
+                struct sockaddr *addr, int *addrlen)
+{
+  size_t cc;
+  char cbuf[128];
+  struct cmsghdr *c;
+  struct iovec iov = { buf, len };
+  struct msghdr msg = { addr, *addrlen,
+                        &iov,  1,
+                        cbuf, sizeof(cbuf),
+                        0 };
+
+  cc = recvmsg(fd, &msg, flags);
+  if (cc < 0)
+    return cc;
+  ((struct sockaddr_in6*)addr)->sin6_flowinfo = 0;
+  *addrlen = msg.msg_namelen;
+  for (c=CMSG_FIRSTHDR(&msg); c; c = CMSG_NEXTHDR(&msg, c)) {
+    if (c->cmsg_level != SOL_IPV6 ||
+      c->cmsg_type != IPV6_FLOWINFO)
+        continue;
+    ((struct sockaddr_in6*)addr)->sin6_flowinfo = *(__u32*)CMSG_DATA(c);
+  }
+  return cc;
+}
+\end{verbatim}
+
+
+
+\section{Flow label management.}
+
+\paragraph{Discussion.}
+\addcontentsline{toc}{subsection}{Discussion}
+Requirements of RFC2460 are pretty tough. Particularly, lifetimes
+longer than boot time require to store allocated labels at stable
+storage, so that the full implementation necessarily includes user space flow
+label manager. There are at least three different approaches:
+
+\begin{enumerate}
+\item {\bf ``Cooperative''. } We could leave flow label allocation wholly
+to user space. When user needs label he requests manager directly. The approach
+is valid, but as any ``cooperative'' approach it suffers of security problems.
+
+\begin{NB}
+One idea is to disallow not privileged user to allocate flow
+labels, but instead to pass the socket to manager via \verb|SCM_RIGHTS|
+control message, so that it will allocate label and assign it to socket
+itself. Hmm... the idea is interesting.
+\end{NB}
+
+\item {\bf ``Indirect''.} Kernel redirects requests to user level daemon
+and does not install label until the daemon acknowledged the request.
+The approach is the most promising, it is especially pleasant to recognize
+parallel with IPsec API [RFC2367,Craig]. Actually, it may share API with
+IPsec.
+
+\item {\bf ``Stupid''.} To allocate labels in kernel space. It is the simplest
+method, but it suffers of two serious flaws: the first,
+we cannot lease labels with lifetimes longer than boot time, the second, 
+it is sensitive to DoS attacks. Kernel have to remember all the obsolete
+labels until their expiration and malicious user may fastly eat all the
+flow label space.
+
+\end{enumerate}
+
+Certainly, I choose the most ``stupid'' method. It is the cheapest one
+for implementor (i.e.\ me), and taking into account that flow labels
+still have no serious applications it is not useful to work on more
+advanced API, especially, taking into account that eventually we
+will get it for no fee together with IPsec.
+
+
+\paragraph{Implementation.}
+\addcontentsline{toc}{subsection}{Implementation}
+Socket option \verb|IPV6_FLOWLABEL_MGR| allows to
+request flow label manager to allocate new flow label, to reuse
+already allocated one or to delete old flow label.
+Its argument is \verb|struct| \verb|in6_flowlabel_req|:
+
+\begin{verbatim}
+struct in6_flowlabel_req
+{
+        struct in6_addr flr_dst;
+        __u32           flr_label;
+        __u8            flr_action;
+        __u8            flr_share;
+        __u16           flr_flags;
+        __u16           flr_expires;
+        __u16           flr_linger;
+        __u32         __flr_reserved;
+        /* Options in format of IPV6_PKTOPTIONS */
+};
+\end{verbatim}
+
+\begin{itemize}
+
+\item \verb|dst| is IPv6 destination address associated with the label.
+
+\item \verb|label| is flow label value in network byte order. If it is zero,
+kernel will allocate new pseudo-random number. Otherwise, kernel will try
+to lease flow label ordered by user. In this case, it is user task to provide
+necessary flow label randomness.
+
+\item \verb|action| is requested operation. Currently, only three operations
+are defined:
+
+\begin{verbatim}
+#define IPV6_FL_A_GET   0   /* Get flow label */
+#define IPV6_FL_A_PUT   1   /* Release flow label */
+#define IPV6_FL_A_RENEW 2   /* Update expire time */
+\end{verbatim}
+
+\item \verb|flags| are optional modifiers. Currently
+only \verb|IPV6_FL_A_GET| has modifiers:
+
+\begin{verbatim}
+#define IPV6_FL_F_CREATE 1   /* Allowed to create new label */
+#define IPV6_FL_F_EXCL   2   /* Do not create new label */
+\end{verbatim}
+
+
+\item \verb|share| defines who is allowed to reuse the same flow label.
+
+\begin{verbatim}
+#define IPV6_FL_S_NONE    0   /* Not defined */
+#define IPV6_FL_S_EXCL    1   /* Label is private */
+#define IPV6_FL_S_PROCESS 2   /* May be reused by this process */
+#define IPV6_FL_S_USER    3   /* May be reused by this user */
+#define IPV6_FL_S_ANY     255 /* Anyone may reuse it */
+\end{verbatim}
+
+\item \verb|linger| is time in seconds. After the last user releases flow
+label, it will not be reused with different destination and options at least
+during this time. If \verb|share| is not \verb|IPV6_FL_S_EXCL| the label
+still can be shared by another sockets. Current implementation does not allow
+unprivileged user to set linger longer than 60 sec.
+
+\item \verb|expires| is time in seconds. Flow label will be kept at least
+for this time, but it will not be destroyed before user released it explicitly
+or closed all the sockets using it. Current implementation does not allow
+unprivileged user to set timeout longer than 60 sec. Proviledged applications
+MAY set longer lifetimes, but in this case they MUST save allocated
+labels at stable storage and restore them back after reboot before the first
+application allocates new flow.
+
+\end{itemize}
+
+This structure is followed by optional extension headers associated
+with this flow label in format of \verb|IPV6_PKTOPTIONS|. Only
+\verb|IPV6_HOPOPTS|, \verb|IPV6_RTHDR| and, if \verb|IPV6_RTHDR| presents,
+\verb|IPV6_DSTOPTS| are allowed.
+
+\paragraph{Example.}
+\addcontentsline{toc}{subsection}{Example}
+ The function \verb|get_flow_label| allocates
+private flow label.
+
+\begin{verbatim}
+int get_flow_label(int fd, struct sockaddr_in6 *dst, __u32 fl)
+{
+        int on = 1;
+        struct in6_flowlabel_req freq;
+
+        memset(&freq, 0, sizeof(freq));
+        freq.flr_label = htonl(fl);
+        freq.flr_action = IPV6_FL_A_GET;
+        freq.flr_flags = IPV6_FL_F_CREATE | IPV6_FL_F_EXCL;
+        freq.flr_share = IPV6_FL_S_EXCL;
+        memcpy(&freq.flr_dst, &dst->sin6_addr, 16);
+        if (setsockopt(fd, SOL_IPV6, IPV6_FLOWLABEL_MGR,
+                       &freq, sizeof(freq)) == -1) {
+                perror ("can't lease flowlabel");
+                return -1;
+        }
+        dst->sin6_flowinfo |= freq.flr_label;
+
+        if (setsockopt(fd, SOL_IPV6, IPV6_FLOWINFO_SEND,
+                       &on, sizeof(on)) == -1) {
+                perror ("can't send flowinfo");
+
+                freq.flr_action = IPV6_FL_A_PUT;
+                setsockopt(fd, SOL_IPV6, IPV6_FLOWLABEL_MGR,
+                           &freq, sizeof(freq));
+                return -1;
+        }
+        return 0;
+}
+\end{verbatim}
+
+A bit more complicated example using routing header can be found
+in \verb|ping6| utility (\verb|iputils| package). Linux rsvpd backend
+contains an example of using operation \verb|IPV6_FL_A_RENEW|.
+
+\paragraph{Listing flow labels.} 
+\addcontentsline{toc}{subsection}{Listing flow labels}
+List of currently allocated
+flow labels may be read from \verb|/proc/net/ip6_flowlabel|.
+
+\begin{verbatim}
+Label S Owner Users Linger Expires Dst                              Opt
+A1BE5 1 0     0     6      3       3ffe2400000000010a0020fffe71fb30 0
+\end{verbatim}
+
+\begin{itemize}
+\item \verb|Label| is hexadecimal flow label value.
+\item \verb|S| is sharing style.
+\item \verb|Owner| is ID of creator, it is zero, pid or uid, depending on
+		sharing style.
+\item \verb|Users| is number of applications using the label now.
+\item \verb|Linger| is \verb|linger| of this label in seconds.
+\item \verb|Expires| is time until expiration of the label in seconds. It may
+	be negative, if the label is in use.
+\item \verb|Dst| is IPv6 destination address.
+\item \verb|Opt| is length of options, associated with the label. Option
+	data are not accessible.
+\end{itemize}
+
+
+\paragraph{Flow labels and RSVP.} 
+\addcontentsline{toc}{subsection}{Flow labels and RSVP}
+RSVP daemon supports IPv6 flow labels
+without any modifications to standard ISI RAPI. Sender must allocate
+flow label, fill corresponding sender template and submit it to local rsvp
+daemon. rsvpd will check the label and start to announce it in PATH
+messages. Rsvpd on sender node will renew the flow label, so that it will not
+be reused before path state expires and all the intermediate
+routers and receiver purge flow state.
+
+\verb|rtap| utility is modified to parse flow labels. F.e.\ if user allocated
+flow label \verb|0xA1234|, he may write:
+
+\begin{verbatim}
+RTAP> sender 3ffe:2400::1/FL0xA1234 <Tspec>
+\end{verbatim}
+
+Receiver makes reservation with command:
+\begin{verbatim}
+RTAP> reserve ff 3ffe:2400::1/FL0xA1234 <Flowspec>
+\end{verbatim}
+
+\end{document}
diff --git a/iproute2/doc/arpd.sgml b/iproute2/doc/arpd.sgml
new file mode 100644
index 0000000..0ab79c6
--- /dev/null
+++ b/iproute2/doc/arpd.sgml
@@ -0,0 +1,130 @@
+<!doctype linuxdoc system>
+
+<article>
+
+<title>ARPD Daemon
+<author>Alexey Kuznetsov, <tt/kuznet@ms2.inr.ac.ru/
+<date>some_negative_number, 20 Sep 2001
+<abstract>
+<tt/arpd/ is daemon collecting gratuitous ARP information, saving
+it on local disk and feeding it to kernel on demand to avoid
+redundant broadcasting due to limited size of kernel ARP cache. 
+</abstract>
+
+
+<p><bf/Description/
+
+<p>The format of the command is:
+
+<tscreen><verb>
+       arpd OPTIONS [ INTERFACE [ INTERFACE ... ] ]
+</verb></tscreen>
+
+<p> <tt/OPTIONS/ are:
+
+<itemize>
+
+<item><tt/-l/ - dump <tt/arpd/ database to stdout and exit. Output consists
+of three columns: interface index, IP address and MAC address.
+Negative entries for dead hosts are also shown, in this case MAC address
+is replaced by word <tt/FAILED/ followed by colon and time when the fact
+that host is dead was proven the last time.
+
+<item><tt/-f FILE/  - read and load <tt/arpd/ database from <tt/FILE/
+in text format similar dumped by option <tt/-l/. Exit after load,
+probably listing resulting database, if option <tt/-l/ is also given.
+If <tt/FILE/ is <tt/-/, <tt/stdin/ is read to get ARP table.
+ 
+<item><tt/-b DATABASE/  - location of database file. Default location is
+<tt>/var/lib/arpd/arpd.db</tt>.
+
+<item><tt/-a NUMBER/ - <tt/arpd/ not only passively listens ARP on wire, but
+also send brodcast queries itself. <tt/NUMBER/ is number of such queries
+to make before destination is considered as dead. When <tt/arpd/ is started
+as kernel helper (i.e. with <tt/app_solicit/ enabled in <tt/sysctl/
+or even with option <tt/-k/) without this option and still did not learn enough
+information, you can observe 1 second gaps in service. Not fatal, but
+not good.
+
+<item><tt/-k/ - suppress sending broadcast queries by kernel. It takes
+sense together with option <tt/-a/.
+
+<item><tt/-n TIME/ - timeout of negative cache. When resolution fails <tt/arpd/
+suppresses further attempts to resolve for this period. It makes sense
+only together with option <tt/-k/. This timeout should not be too much
+longer than boot time of a typical host not supporting gratuitous ARP.
+Default value is 60 seconds.
+
+<item><tt/-R RATE/ - maximal steady rate of broadcasts sent by <tt/arpd/
+in packets per second. Default value is 1.
+
+<item><tt/-B NUMBER/ - number of broadcasts sent by <tt/arpd/ back to back.
+Default value is 3. Together with option <tt/-R/ this option allows
+to police broadcasting not to exceed <tt/B+R*T/ over any interval
+of time <tt/T/.
+
+</itemize>
+
+<p><tt/INTERFACE/ is name of networking inteface to watch.
+If no interfaces given, <tt/arpd/ monitors all the interfaces.
+In this case <tt/arpd/ does not adjust <tt/sysctl/ parameters,
+it is supposed user does this himself after <tt/arpd/ is started.
+
+
+<p> Signals
+
+<p> <tt/arpd/ exits gracefully syncing database and restoring adjusted
+<tt/sysctl/ parameters, when receives <tt/SIGINT/ or <tt/SIGTERM/.
+<tt/SIGHUP/ syncs database to disk. <tt/SIGUSR1/ sends some statistics
+to <tt/syslog/. Effect of another signals is undefined, they may corrupt
+database and leave <tt/sysctl/ parameters in an unpredictable state.
+
+<p> Note
+
+<p> In order to <tt/arpd/ be able to serve as ARP resolver, kernel must be
+compiled with the option <tt/CONFIG_ARPD/ and, in the case when interface list
+is not given on command line, variable <tt/app_solicit/
+on interfaces of interest should be set in <tt>/proc/sys/net/ipv4/neigh/*</tt>.
+If this is not made <tt/arpd/ still collects gratuitous ARP information
+in its database.
+
+<p> Examples
+
+<enum>
+<item> Start <tt/arpd/ to collect gratuitous ARP, but not messing
+with kernel functionality:
+
+<tscreen><verb>
+   arpd -b /var/tmp/arpd.db
+</verb></tscreen>
+
+<item> Look at result after some time:
+
+<tscreen><verb>
+   killall arpd
+   arpd -l -b /var/tmp/arpd.db
+</verb></tscreen>
+
+<item> To enable kernel helper, leaving leading role to kernel:
+
+<tscreen><verb>
+   arpd -b /var/tmp/arpd.db -a 1 eth0 eth1
+</verb></tscreen>
+
+<item> Completely replace kernel resolution on interfaces <tt/eth0/
+and <tt/eth1/. In this case kernel still does unicast probing to
+validate entries, but all the broadcast activity is suppressed
+and made under authority of <tt/arpd/: 
+
+<tscreen><verb>
+   arpd -b /var/tmp/arpd.db -a 3 -k eth0 eth1
+</verb></tscreen>
+
+This is mode which <tt/arpd/ is supposed to work normally.
+It is not default just to prevent occasional enabling of too aggressive
+mode occasionally.
+
+</enum>
+
+</article>
+
diff --git a/iproute2/doc/do-psnup b/iproute2/doc/do-psnup
new file mode 100644
index 0000000..2dce848
--- /dev/null
+++ b/iproute2/doc/do-psnup
@@ -0,0 +1,16 @@
+#! /bin/bash
+# $1 = Temporary file . "string"
+# $2 = File to process . "string"
+# $3 = Page size . ie: a4 , letter ... "string"
+# $4 = Number of pages to fit on a single sheet . "numeric"
+
+if type psnup >&/dev/null; then
+	echo "psnup -$4 -p$3 $1 $2"
+	psnup -$4 -p$3 $1 $2
+elif type psmulti >&/dev/null; then
+	echo "psmulti $1 > $2"
+	psmulti $1 > $2
+else
+	echo "cp $1 $2"
+	cp $1 $2
+fi
diff --git a/iproute2/doc/ip-cref.tex b/iproute2/doc/ip-cref.tex
new file mode 100644
index 0000000..67094c9
--- /dev/null
+++ b/iproute2/doc/ip-cref.tex
@@ -0,0 +1,3449 @@
+\documentstyle[12pt,twoside]{article}
+\def\TITLE{IP Command Reference}
+\input preamble
+\begin{center}
+\Large\bf IP Command Reference.
+\end{center}
+
+
+\begin{center}
+{ \large Alexey~N.~Kuznetsov } \\
+\em Institute for Nuclear Research, Moscow \\
+\verb|kuznet@ms2.inr.ac.ru| \\
+\rm April 14, 1999
+\end{center}
+
+\vspace{5mm}
+
+\tableofcontents
+
+\newpage
+
+\section{About this document}
+
+This document presents a comprehensive description of the \verb|ip| utility
+from the \verb|iproute2| package. It is not a tutorial or user's guide.
+It is a {\em dictionary\/}, not explaining terms,
+but translating them into other terms, which may also be unknown to the reader.
+However, the document is self-contained and the reader, provided they have a
+basic networking background, will find enough information
+and examples to understand and configure Linux-2.2 IP and IPv6
+networking.
+
+This document is split into sections explaining \verb|ip| commands
+and options, decrypting \verb|ip| output and containing a few examples.
+More voluminous examples and some topics, which require more elaborate
+discussion, are in the appendix.
+
+The paragraphs beginning with NB contain side notes, warnings about
+bugs and design drawbacks. They may be skipped at the first reading.
+
+\section{{\tt ip} --- command syntax}
+
+The generic form of an \verb|ip| command is:
+\begin{verbatim}
+ip [ OPTIONS ] OBJECT [ COMMAND [ ARGUMENTS ]]
+\end{verbatim}
+where \verb|OPTIONS| is a set of optional modifiers affecting the
+general behaviour of the \verb|ip| utility or changing its output. All options
+begin with the character \verb|'-'| and may be used in either long or abbreviated 
+forms. Currently, the following options are available:
+
+\begin{itemize}
+\item \verb|-V|, \verb|-Version|
+
+--- print the version of the \verb|ip| utility and exit.
+
+
+\item \verb|-s|, \verb|-stats|, \verb|-statistics|
+
+--- output more information. If the option
+appears twice or more, the amount of information increases.
+As a rule, the information is statistics or some time values.
+
+\item \verb|-d|, \verb|-details|
+
+--- output more detailed information.
+
+\item \verb|-f|, \verb|-family| followed by a protocol family
+identifier: \verb|inet|, \verb|inet6| or \verb|link|.
+
+--- enforce the protocol family to use. If the option is not present,
+the protocol family is guessed from other arguments. If the rest of the command
+line does not give enough information to guess the family, \verb|ip| falls back to the default
+one, usually \verb|inet| or \verb|any|. \verb|link| is a special family
+identifier meaning that no networking protocol is involved.
+
+\item \verb|-4|
+
+--- shortcut for \verb|-family inet|.
+
+\item \verb|-6|
+
+--- shortcut for \verb|-family inet6|.
+
+\item \verb|-0|
+
+--- shortcut for \verb|-family link|.
+
+
+\item \verb|-o|, \verb|-oneline|
+
+--- output each record on a single line, replacing line feeds
+with the \verb|'\'| character. This is convenient when you want to
+count records with \verb|wc| or to \verb|grep| the output. The trivial
+script \verb|rtpr| converts the output back into readable form.
+
+\item \verb|-r|, \verb|-resolve|
+
+--- use the system's name resolver to print DNS names instead of
+host addresses.
+
+\begin{NB}
+ Do not use this option when reporting bugs or asking for advice.
+\end{NB}
+\begin{NB}
+ \verb|ip| never uses DNS to resolve names to addresses.
+\end{NB}
+
+\item \verb|-b|, \verb|-batch FILE|
+
+--- read commands from provided file or standart input and invoke them.
+First failure will cause termination of \verb|ip|.
+In batch \verb|FILE| everything which begins with \verb|#| symbol is
+ignored and can be used for comments.
+\paragraph{Example:}
+\begin{verbatim}
+kuznet@kaiser $ cat /tmp/ip_batch.ip
+# This is a comment
+tuntap add mode tap tap1 # This is an another comment
+link set up dev tap1
+addr add 10.0.0.1/24 dev tap1
+kuznet@kaiser $ sudo ip -b /tmp/ip_batch.ip
+\end{verbatim}
+or from standart input:
+\begin{verbatim}
+kuznet@kaiser $ cat /tmp/ip_batch.ip | sudo ip -b -
+\end{verbatim}
+
+\item \verb|-force|
+
+--- don't terminate ip on errors in batch mode.
+If there were any errors during execution of the commands,
+the application return code will be non zero.
+
+\item \verb|-l|, \verb|-loops COUNT|
+
+--- specify maximum number of loops the 'ip addr flush' logic will attempt
+before giving up. The default is 10.  Zero (0) means loop until all
+addresses are removed.
+
+\end{itemize}
+
+\verb|OBJECT| is the object to manage or to get information about.
+The object types currently understood by \verb|ip| are:
+
+\begin{itemize}
+\item \verb|link| --- network device
+\item \verb|address| --- protocol (IP or IPv6) address on a device
+\item \verb|neighbour| --- ARP or NDISC cache entry
+\item \verb|route| --- routing table entry
+\item \verb|rule| --- rule in routing policy database
+\item \verb|maddress| --- multicast address
+\item \verb|mroute| --- multicast routing cache entry
+\item \verb|tunnel| --- tunnel over IP
+\end{itemize}
+
+Again, the names of all objects may be written in full or
+abbreviated form, f.e.\ \verb|address| is abbreviated as \verb|addr|
+or just \verb|a|.
+
+\verb|COMMAND| specifies the action to perform on the object.
+The set of possible actions depends on the object type.
+As a rule, it is possible to \verb|add|, \verb|delete| and
+\verb|show| (or \verb|list|) objects, but some objects
+do not allow all of these operations or have some additional commands.
+The \verb|help| command is available for all objects. It prints
+out a list of available commands and argument syntax conventions.
+
+If no command is given, some default command is assumed.
+Usually it is \verb|list| or, if the objects of this class
+cannot be listed, \verb|help|.
+
+\verb|ARGUMENTS| is a list of arguments to the command.
+The arguments depend on the command and object. There are two types of arguments:
+{\em flags\/}, consisting of a single keyword, and {\em parameters\/},
+consisting of a keyword followed by a value. For convenience,
+each command has some {\em default parameter\/}
+which may be omitted. F.e.\ parameter \verb|dev| is the default
+for the {\tt ip link} command, so {\tt ip link ls eth0} is equivalent
+to {\tt ip link ls dev eth0}.
+In the command descriptions below such parameters
+are distinguished with the marker: ``(default)''.
+
+Almost all keywords may be abbreviated with several first (or even single)
+letters. The shortcuts are convenient when \verb|ip| is used interactively,
+but they are not recommended in scripts or when reporting bugs
+or asking for advice. ``Officially'' allowed abbreviations are listed
+in the document body.
+
+
+
+\section{{\tt ip} --- error messages}
+
+\verb|ip| may fail for one of the following reasons:
+
+\begin{itemize}
+\item
+A syntax error on the command line: an unknown keyword, incorrectly formatted
+IP address {\em et al\/}. In this case \verb|ip| prints an error message
+and exits. As a rule, the error message will contain information
+about the reason for the failure. Sometimes it also prints a help page.
+
+\item
+The arguments did not pass verification for self-consistency.
+
+\item
+\verb|ip| failed to compile a kernel request from the arguments
+because the user didn't give enough information.
+
+\item
+The kernel returned an error to some syscall. In this case \verb|ip|
+prints the error message, as it is output with \verb|perror(3)|,
+prefixed with a comment and a syscall identifier.
+
+\item
+The kernel returned an error to some RTNETLINK request.
+In this case \verb|ip| prints the error message, as it is output
+with \verb|perror(3)| prefixed with ``RTNETLINK answers:''.
+
+\end{itemize}
+
+All the operations are atomic, i.e.\ 
+if the \verb|ip| utility fails, it does not change anything
+in the system. One harmful exception is \verb|ip link| command
+(Sec.\ref{IP-LINK}, p.\pageref{IP-LINK}),
+which may change only some of the device parameters given
+on command line.
+
+It is difficult to list all the error messages (especially
+syntax errors). However, as a rule, their meaning is clear
+from the context of the command.
+
+The most common mistakes are:
+
+\begin{enumerate}
+\item Netlink is not configured in the kernel. The message is:
+\begin{verbatim}
+Cannot open netlink socket: Invalid value
+\end{verbatim}
+
+\item RTNETLINK is not configured in the kernel. In this case
+one of the following messages may be printed, depending on the command:
+\begin{verbatim}
+Cannot talk to rtnetlink: Connection refused
+Cannot send dump request: Connection refused
+\end{verbatim}
+
+\item The \verb|CONFIG_IP_MULTIPLE_TABLES| option was not selected
+when configuring the kernel. In this case any attempt to use the
+\verb|ip| \verb|rule| command will fail, f.e.
+\begin{verbatim}
+kuznet@kaiser $ ip rule list
+RTNETLINK error: Invalid argument
+dump terminated
+\end{verbatim}
+
+\end{enumerate}
+
+
+\section{{\tt ip link} --- network device configuration}
+\label{IP-LINK}
+
+\paragraph{Object:} A \verb|link| is a network device and the corresponding
+commands display and change the state of devices.
+
+\paragraph{Commands:} \verb|set| and \verb|show| (or \verb|list|).
+
+\subsection{{\tt ip link set} --- change device attributes}
+
+\paragraph{Abbreviations:} \verb|set|, \verb|s|.
+
+\paragraph{Arguments:}
+
+\begin{itemize}
+\item \verb|dev NAME| (default)
+
+--- \verb|NAME| specifies the network device on which to operate.
+
+\item \verb|up| and \verb|down|
+
+--- change the state of the device to \verb|UP| or \verb|DOWN|.
+
+\item \verb|arp on| or \verb|arp off|
+
+--- change the \verb|NOARP| flag on the device.
+
+\begin{NB}
+This operation is {\em not allowed\/} if the device is in state \verb|UP|.
+Though neither the \verb|ip| utility nor the kernel check for this condition.
+You can get unpredictable results changing this flag while the
+device is running.
+\end{NB}
+
+\item \verb|multicast on| or \verb|multicast off|
+
+--- change the \verb|MULTICAST| flag on the device.
+
+\item \verb|dynamic on| or \verb|dynamic off|
+
+--- change the \verb|DYNAMIC| flag on the device.
+
+\item \verb|name NAME|
+
+--- change the name of the device. This operation is not
+recommended if the device is running or has some addresses
+already configured.
+
+\item \verb|txqueuelen NUMBER| or \verb|txqlen NUMBER|
+
+--- change the transmit queue length of the device.
+
+\item \verb|mtu NUMBER|
+
+--- change the MTU of the device.
+
+\item \verb|address LLADDRESS|
+
+--- change the station address of the interface.
+
+\item \verb|broadcast LLADDRESS|, \verb|brd LLADDRESS| or \verb|peer LLADDRESS|
+
+--- change the link layer broadcast address or the peer address when
+the interface is \verb|POINTOPOINT|.
+
+\vskip 1mm
+\begin{NB}
+For most devices (f.e.\ for Ethernet) changing the link layer
+broadcast address will break networking.
+Do not use it, if you do not understand what this operation really does.
+\end{NB}
+
+\item \verb|netns PID|
+
+--- move the device to the network namespace associated with the process PID.
+
+\end{itemize}
+
+\vskip 1mm
+\begin{NB}
+The \verb|PROMISC| and \verb|ALLMULTI| flags are considered
+obsolete and should not be changed administratively, though
+the {\tt ip} utility will allow that.
+\end{NB}
+
+\paragraph{Warning:} If multiple parameter changes are requested,
+\verb|ip| aborts immediately after any of the changes have failed.
+This is the only case when \verb|ip| can move the system to
+an unpredictable state. The solution is to avoid changing
+several parameters with one {\tt ip link set} call.
+
+\paragraph{Examples:}
+\begin{itemize}
+\item \verb|ip link set dummy address 00:00:00:00:00:01|
+
+--- change the station address of the interface \verb|dummy|.
+
+\item \verb|ip link set dummy up|
+
+--- start the interface \verb|dummy|.
+
+\end{itemize}
+
+
+\subsection{{\tt ip link show} --- display device attributes}
+\label{IP-LINK-SHOW}
+
+\paragraph{Abbreviations:} \verb|show|, \verb|list|, \verb|lst|, \verb|sh|, \verb|ls|,
+\verb|l|.
+
+\paragraph{Arguments:}
+\begin{itemize}
+\item \verb|dev NAME| (default)
+
+--- \verb|NAME| specifies the network device to show.
+If this argument is omitted all devices are listed.
+
+\item \verb|up|
+
+--- only display running interfaces.
+
+\end{itemize}
+
+
+\paragraph{Output format:}
+
+\begin{verbatim}
+kuznet@alisa:~ $ ip link ls eth0
+3: eth0: <BROADCAST,MULTICAST,UP> mtu 1500 qdisc cbq qlen 100
+    link/ether 00:a0:cc:66:18:78 brd ff:ff:ff:ff:ff:ff
+kuznet@alisa:~ $ ip link ls sit0
+5: sit0@NONE: <NOARP,UP> mtu 1480 qdisc noqueue
+    link/sit 0.0.0.0 brd 0.0.0.0
+kuznet@alisa:~ $ ip link ls dummy
+2: dummy: <BROADCAST,NOARP> mtu 1500 qdisc noop
+    link/ether 00:00:00:00:00:00 brd ff:ff:ff:ff:ff:ff
+kuznet@alisa:~ $ 
+\end{verbatim}
+
+
+The number before each colon is an {\em interface index\/} or {\em ifindex\/}.
+This number uniquely identifies the interface. This is followed by the {\em interface name\/}
+(\verb|eth0|, \verb|sit0| etc.). The interface name is also
+unique at every given moment. However, the interface may disappear from the
+list (f.e.\ when the corresponding driver module is unloaded) and another
+one with the same name may be created later. Besides that,
+the administrator may change the name of any device with
+\verb|ip| \verb|link| \verb|set| \verb|name|
+to make it more intelligible.
+
+The interface name may have another name or \verb|NONE| appended 
+after the \verb|@| sign. This means that this device is bound to some other
+device,
+i.e.\ packets send through it are encapsulated and sent via the ``master''
+device. If the name is \verb|NONE|, the master is unknown.
+
+Then we see the interface {\em mtu\/} (``maximal transfer unit''). This determines
+the maximal size of data which can be sent as a single packet over this interface.
+
+{\em qdisc\/} (``queuing discipline'') shows the queuing algorithm used
+on the interface. Particularly, \verb|noqueue| means that this interface
+does not queue anything and \verb|noop| means that the interface is in blackhole
+mode i.e.\ all packets sent to it are immediately discarded.
+{\em qlen\/} is the default transmit queue length of the device measured
+in packets.
+
+The interface flags are summarized in the angle brackets.
+
+\begin{itemize}
+\item \verb|UP| --- the device is turned on. It is ready to accept
+packets for transmission and it may inject into the kernel packets received
+from other nodes on the network.
+
+\item \verb|LOOPBACK| --- the interface does not communicate with other
+hosts. All packets sent through it will be returned
+and nothing but bounced packets can be received.
+
+\item \verb|BROADCAST| --- the device has the facility to send packets
+to all hosts sharing the same link. A typical example is an Ethernet link.
+
+\item \verb|POINTOPOINT| --- the link has only two ends with one node
+attached to each end. All packets sent to this link will reach the peer
+and all packets received by us came from this single peer.
+
+If neither \verb|LOOPBACK| nor \verb|BROADCAST| nor \verb|POINTOPOINT|
+are set, the interface is assumed to be NMBA (Non-Broadcast Multi-Access).
+This is the most generic type of device and the most complicated one, because
+the host attached to a NBMA link has no means to send to anyone
+without additionally configured information.
+
+\item \verb|MULTICAST| --- is an advisory flag indicating that the interface
+is aware of multicasting i.e.\ sending packets to some subset of neighbouring
+nodes. Broadcasting is a particular case of multicasting, where the multicast
+group consists of all nodes on the link. It is important to emphasize
+that software {\em must not\/} interpret the absence of this flag as the inability
+to use multicasting on this interface. Any \verb|POINTOPOINT| and
+\verb|BROADCAST| link is multicasting by definition, because we have
+direct access to all the neighbours and, hence, to any part of them.
+Certainly, the use of high bandwidth multicast transfers is not recommended
+on broadcast-only links because of high expense, but it is not strictly
+prohibited.
+
+\item \verb|PROMISC| --- the device listens to and feeds to the kernel all
+traffic on the link even if it is not destined for us, not broadcasted
+and not destined for a multicast group of which we are member. Usually
+this mode exists only on broadcast links and is used by bridges and for network
+monitoring.
+
+\item \verb|ALLMULTI| --- the device receives all multicast packets
+wandering on the link. This mode is used by multicast routers.
+
+\item \verb|NOARP| --- this flag is different from the other ones. It has
+no invariant value and its interpretation depends on the network protocols
+involved. As a rule, it indicates that the device needs no address
+resolution and that the software or hardware knows how to deliver packets
+without any help from the protocol stacks.
+
+\item \verb|DYNAMIC| --- is an advisory flag indicating that the interface is
+dynamically created and destroyed.
+
+\item \verb|SLAVE| --- this interface is bonded to some other interfaces
+to share link capacities.
+
+\end{itemize}
+
+\vskip 1mm
+\begin{NB}
+There are other flags but they are either obsolete (\verb|NOTRAILERS|)
+or not implemented (\verb|DEBUG|) or specific to some devices
+(\verb|MASTER|, \verb|AUTOMEDIA| and \verb|PORTSEL|). We do not discuss
+them here.
+\end{NB}
+
+
+The second line contains information on the link layer addresses
+associated with the device. The first word (\verb|ether|, \verb|sit|)
+defines the interface hardware type. This type determines the format and semantics
+of the addresses and is logically part of the address.
+The default format of the station address and the broadcast address
+(or the peer address for pointopoint links) is a
+sequence of hexadecimal bytes separated by colons, but some link
+types may have their natural address format, f.e.\ addresses
+of tunnels over IP are printed as dotted-quad IP addresses.
+
+\vskip 1mm
+\begin{NB}
+  NBMA links have no well-defined broadcast or peer address,
+  however this field may contain useful information, f.e.\
+  about the address of broadcast relay or about the address of the ARP server.
+\end{NB}
+\begin{NB}
+Multicast addresses are not shown by this command, see
+\verb|ip maddr ls| in~Sec.\ref{IP-MADDR} (p.\pageref{IP-MADDR} of this
+document).
+\end{NB}
+
+
+\paragraph{Statistics:} With the \verb|-statistics| option, \verb|ip| also
+prints interface statistics:
+
+\begin{verbatim}
+kuznet@alisa:~ $ ip -s link ls eth0
+3: eth0: <BROADCAST,MULTICAST,UP> mtu 1500 qdisc cbq qlen 100
+    link/ether 00:a0:cc:66:18:78 brd ff:ff:ff:ff:ff:ff
+    RX: bytes  packets  errors  dropped overrun mcast   
+    2449949362 2786187  0       0       0       0      
+    TX: bytes  packets  errors  dropped carrier collsns 
+    178558497  1783945  332     0       332     35172  
+kuznet@alisa:~ $
+\end{verbatim}
+\verb|RX:| and \verb|TX:| lines summarize receiver and transmitter
+statistics. They contain:
+\begin{itemize}
+\item \verb|bytes| --- the total number of bytes received or transmitted
+on the interface. This number wraps when the maximal length of the data type
+natural for the architecture is exceeded, so continuous monitoring requires
+a user level daemon snapping it periodically.
+\item \verb|packets| --- the total number of packets received or transmitted
+on the interface.
+\item \verb|errors| --- the total number of receiver or transmitter errors.
+\item \verb|dropped| --- the total number of packets dropped due to lack
+of resources.
+\item \verb|overrun| --- the total number of receiver overruns resulting
+in dropped packets. As a rule, if the interface is overrun, it means
+serious problems in the kernel or that your machine is too slow
+for this interface.
+\item \verb|mcast| --- the total number of received multicast packets. This option
+is only supported by a few devices.
+\item \verb|carrier| --- total number of link media failures f.e.\ because
+of lost carrier.
+\item \verb|collsns| --- the total number of collision events
+on Ethernet-like media. This number may have a different sense on other
+link types.
+\item \verb|compressed| --- the total number of compressed packets. This is
+available only for links using VJ header compression.
+\end{itemize}
+
+
+If the \verb|-s| option is entered twice or more,
+\verb|ip| prints more detailed statistics on receiver
+and transmitter errors.
+
+\begin{verbatim}
+kuznet@alisa:~ $ ip -s -s link ls eth0
+3: eth0: <BROADCAST,MULTICAST,UP> mtu 1500 qdisc cbq qlen 100
+    link/ether 00:a0:cc:66:18:78 brd ff:ff:ff:ff:ff:ff
+    RX: bytes  packets  errors  dropped overrun mcast   
+    2449949362 2786187  0       0       0       0      
+    RX errors: length   crc     frame   fifo    missed
+               0        0       0       0       0      
+    TX: bytes  packets  errors  dropped carrier collsns 
+    178558497  1783945  332     0       332     35172  
+    TX errors: aborted  fifo    window  heartbeat
+               0        0       0       332    
+kuznet@alisa:~ $
+\end{verbatim}
+These error names are pure Ethernetisms. Other devices
+may have non zero values in these fields but they may be
+interpreted differently.
+
+
+\section{{\tt ip address} --- protocol address management}
+
+\paragraph{Abbreviations:} \verb|address|, \verb|addr|, \verb|a|.
+
+\paragraph{Object:} The \verb|address| is a protocol (IP or IPv6) address attached
+to a network device. Each device must have at least one address
+to use the corresponding protocol. It is possible to have several
+different addresses attached to one device. These addresses are not
+discriminated, so that the term {\em alias\/} is not quite appropriate
+for them and we do not use it in this document.
+
+The \verb|ip addr| command displays addresses and their properties,
+adds new addresses and deletes old ones.
+
+\paragraph{Commands:} \verb|add|, \verb|delete|, \verb|flush| and \verb|show|
+(or \verb|list|).
+
+
+\subsection{{\tt ip address add} --- add a new protocol address}
+\label{IP-ADDR-ADD}
+
+\paragraph{Abbreviations:} \verb|add|, \verb|a|.
+
+\paragraph{Arguments:}
+
+\begin{itemize}
+\item \verb|dev NAME|
+
+\noindent--- the name of the device to add the address to.
+
+\item \verb|local ADDRESS| (default)
+
+--- the address of the interface. The format of the address depends
+on the protocol. It is a dotted quad for IP and a sequence of hexadecimal halfwords
+separated by colons for IPv6. The \verb|ADDRESS| may be followed by
+a slash and a decimal number which encodes the network prefix length.
+
+
+\item \verb|peer ADDRESS|
+
+--- the address of the remote endpoint for pointopoint interfaces.
+Again, the \verb|ADDRESS| may be followed by a slash and a decimal number,
+encoding the network prefix length. If a peer address is specified,
+the local address {\em cannot\/} have a prefix length. The network prefix is associated
+with the peer rather than with the local address.
+
+
+\item \verb|broadcast ADDRESS|
+
+--- the broadcast address on the interface.
+
+It is possible to use the special symbols \verb|'+'| and \verb|'-'|
+instead of the broadcast address. In this case, the broadcast address
+is derived by setting/resetting the host bits of the interface prefix.
+
+\vskip 1mm
+\begin{NB}
+Unlike \verb|ifconfig|, the \verb|ip| utility {\em does not\/} set any broadcast
+address unless explicitly requested.
+\end{NB}
+
+
+\item \verb|label NAME|
+
+--- Each address may be tagged with a label string.
+In order to preserve compatibility with Linux-2.0 net aliases,
+this string must coincide with the name of the device or must be prefixed
+with the device name followed by colon.
+
+
+\item \verb|scope SCOPE_VALUE|
+
+--- the scope of the area where this address is valid.
+The available scopes are listed in file \verb|/etc/iproute2/rt_scopes|.
+Predefined scope values are:
+
+ \begin{itemize}
+	\item \verb|global| --- the address is globally valid.
+	\item \verb|site| --- (IPv6 only) the address is site local,
+	i.e.\ it is valid inside this site.
+	\item \verb|link| --- the address is link local, i.e.\ 
+	it is valid only on this device.
+	\item \verb|host| --- the address is valid only inside this host.
+ \end{itemize}
+
+Appendix~\ref{ADDR-SEL} (p.\pageref{ADDR-SEL} of this document)
+contains more details on address scopes.
+
+\end{itemize}
+
+\paragraph{Examples:}
+\begin{itemize}
+\item \verb|ip addr add 127.0.0.1/8 dev lo brd + scope host|
+
+--- add the usual loopback address to the loopback device.
+
+\item \verb|ip addr add 10.0.0.1/24 brd + dev eth0 label eth0:Alias|
+
+--- add the address 10.0.0.1 with prefix length 24 (i.e.\ netmask
+\verb|255.255.255.0|), standard broadcast and label \verb|eth0:Alias|
+to the interface \verb|eth0|.
+\end{itemize}
+
+
+\subsection{{\tt ip address delete} --- delete a protocol address}
+
+\paragraph{Abbreviations:} \verb|delete|, \verb|del|, \verb|d|.
+
+\paragraph{Arguments:} coincide with the arguments of \verb|ip addr add|.
+The device name is a required argument. The rest are optional.
+If no arguments are given, the first address is deleted.
+
+\paragraph{Examples:}
+\begin{itemize}
+\item \verb|ip addr del 127.0.0.1/8 dev lo|
+
+--- deletes the loopback address from the loopback device.
+It would be best not to repeat this experiment.
+
+\item Disable IP on the interface \verb|eth0|:
+\begin{verbatim}
+  while ip -f inet addr del dev eth0; do
+    : nothing
+  done
+\end{verbatim}
+Another method to disable IP on an interface using {\tt ip addr flush}
+may be found in sec.\ref{IP-ADDR-FLUSH}, p.\pageref{IP-ADDR-FLUSH}.
+
+\end{itemize}
+
+
+\subsection{{\tt ip address show} --- display protocol addresses}
+
+\paragraph{Abbreviations:} \verb|show|, \verb|list|, \verb|lst|, \verb|sh|, \verb|ls|,
+\verb|l|.
+
+\paragraph{Arguments:}
+
+\begin{itemize}
+\item \verb|dev NAME| (default)
+
+--- the name of the device.
+
+\item \verb|scope SCOPE_VAL|
+
+--- only list addresses with this scope.
+
+\item \verb|to PREFIX|
+
+--- only list addresses matching this prefix.
+
+\item \verb|label PATTERN|
+
+--- only list addresses with labels matching the \verb|PATTERN|.
+\verb|PATTERN| is a usual shell style pattern.
+
+
+\item \verb|dynamic| and \verb|permanent|
+
+--- (IPv6 only) only list addresses installed due to stateless
+address configuration or only list permanent (not dynamic) addresses.
+
+\item \verb|tentative|
+
+--- (IPv6 only) only list addresses which did not pass duplicate
+address detection.
+
+\item \verb|deprecated|
+
+--- (IPv6 only) only list deprecated addresses.
+
+
+\item  \verb|primary| and \verb|secondary|
+
+--- only list primary (or secondary) addresses.
+
+\end{itemize}
+
+
+\paragraph{Output format:}
+
+\begin{verbatim}
+kuznet@alisa:~ $ ip addr ls eth0
+3: eth0: <BROADCAST,MULTICAST,UP> mtu 1500 qdisc cbq qlen 100
+    link/ether 00:a0:cc:66:18:78 brd ff:ff:ff:ff:ff:ff
+    inet 193.233.7.90/24 brd 193.233.7.255 scope global eth0
+    inet6 3ffe:2400:0:1:2a0:ccff:fe66:1878/64 scope global dynamic 
+       valid_lft forever preferred_lft 604746sec
+    inet6 fe80::2a0:ccff:fe66:1878/10 scope link 
+kuznet@alisa:~ $ 
+\end{verbatim}
+
+The first two lines coincide with the output of \verb|ip link ls|.
+It is natural to interpret link layer addresses
+as addresses of the protocol family \verb|AF_PACKET|.
+
+Then the list of IP and IPv6 addresses follows, accompanied by
+additional address attributes: scope value (see Sec.\ref{IP-ADDR-ADD},
+p.\pageref{IP-ADDR-ADD} above), flags and the address label.
+
+Address flags are set by the kernel and cannot be changed
+administratively. Currently, the following flags are defined:
+
+\begin{enumerate}
+\item \verb|secondary|
+
+--- the address is not used when selecting the default source address
+of outgoing packets (Cf.\ Appendix~\ref{ADDR-SEL}, p.\pageref{ADDR-SEL}.).
+An IP address becomes secondary if another address with the same
+prefix bits already exists. The first address is primary.
+It is the leader of the group of all secondary addresses. When the leader
+is deleted, all secondaries are purged too.
+There is a tweak in \verb|/proc/sys/net/ipv4/conf/<dev>/promote_secondaries|
+which activate secondaries promotion when a primary is deleted.
+To permanently enable this feature on all devices add
+\verb|net.ipv4.conf.all.promote_secondaries=1| to \verb|/etc/sysctl.conf|.
+This tweak is available in linux 2.6.15 and later.
+
+
+\item \verb|dynamic|
+
+--- the address was created due to stateless autoconfiguration~\cite{RFC-ADDRCONF}.
+In this case the output also contains information on times, when
+the address is still valid. After \verb|preferred_lft| expires the address is
+moved to the deprecated state. After \verb|valid_lft| expires the address
+is finally invalidated.
+
+\item \verb|deprecated|
+
+--- the address is deprecated, i.e.\ it is still valid, but cannot
+be used by newly created connections.
+
+\item \verb|tentative|
+
+--- the address is not used because duplicate address detection~\cite{RFC-ADDRCONF}
+is still not complete or failed.
+
+\end{enumerate}
+
+
+\subsection{{\tt ip address flush} --- flush protocol addresses}
+\label{IP-ADDR-FLUSH}
+
+\paragraph{Abbreviations:} \verb|flush|, \verb|f|.
+
+\paragraph{Description:}This command flushes the protocol addresses
+selected by some criteria.
+
+\paragraph{Arguments:} This command has the same arguments as \verb|show|.
+The difference is that it does not run when no arguments are given.
+
+\paragraph{Warning:} This command (and other \verb|flush| commands
+described below) is pretty dangerous. If you make a mistake, it will
+not forgive it, but will cruelly purge all the addresses.
+
+\paragraph{Statistics:} With the \verb|-statistics| option, the command
+becomes verbose. It prints out the number of deleted addresses and the number
+of rounds made to flush the address list. If this option is given
+twice, \verb|ip addr flush| also dumps all the deleted addresses
+in the format described in the previous subsection.
+
+\paragraph{Example:} Delete all the addresses from the private network
+10.0.0.0/8:
+\begin{verbatim}
+netadm@amber:~ # ip -s -s a f to 10/8
+2: dummy    inet 10.7.7.7/16 brd 10.7.255.255 scope global dummy
+3: eth0    inet 10.10.7.7/16 brd 10.10.255.255 scope global eth0
+4: eth1    inet 10.8.7.7/16 brd 10.8.255.255 scope global eth1
+
+*** Round 1, deleting 3 addresses ***
+*** Flush is complete after 1 round ***
+netadm@amber:~ # 
+\end{verbatim}
+Another instructive example is disabling IP on all the Ethernets:
+\begin{verbatim}
+netadm@amber:~ # ip -4 addr flush label "eth*"
+\end{verbatim}
+And the last example shows how to flush all the IPv6 addresses
+acquired by the host from stateless address autoconfiguration
+after you enabled forwarding or disabled autoconfiguration.
+\begin{verbatim}
+netadm@amber:~ # ip -6 addr flush dynamic
+\end{verbatim}
+
+
+
+\section{{\tt ip neighbour} --- neighbour/arp tables management}
+
+\paragraph{Abbreviations:} \verb|neighbour|, \verb|neighbor|, \verb|neigh|,
+\verb|n|.
+
+\paragraph{Object:} \verb|neighbour| objects establish bindings between protocol
+addresses and link layer addresses for hosts sharing the same link.
+Neighbour entries are organized into tables. The IPv4 neighbour table
+is known by another name --- the ARP table.
+
+The corresponding commands display neighbour bindings
+and their properties, add new neighbour entries and delete old ones.
+
+\paragraph{Commands:} \verb|add|, \verb|change|, \verb|replace|,
+\verb|delete|, \verb|flush| and \verb|show| (or \verb|list|).
+
+\paragraph{See also:} Appendix~\ref{PROXY-NEIGH}, p.\pageref{PROXY-NEIGH}
+describes how to manage proxy ARP/NDISC with the \verb|ip| utility.
+
+
+\subsection{{\tt ip neighbour add} --- add a new neighbour entry\\
+	{\tt ip neighbour change} --- change an existing entry\\
+	{\tt ip neighbour replace} --- add a new entry or change an existing one}
+
+\paragraph{Abbreviations:} \verb|add|, \verb|a|; \verb|change|, \verb|chg|;
+\verb|replace|,	\verb|repl|.
+
+\paragraph{Description:} These commands create new neighbour records
+or update existing ones.
+
+\paragraph{Arguments:}
+
+\begin{itemize}
+\item \verb|to ADDRESS| (default)
+
+--- the protocol address of the neighbour. It is either an IPv4 or IPv6 address.
+
+\item \verb|dev NAME|
+
+--- the interface to which this neighbour is attached.
+
+
+\item \verb|lladdr LLADDRESS|
+
+--- the link layer address of the neighbour. \verb|LLADDRESS| can also be
+\verb|null|. 
+
+\item \verb|nud NUD_STATE|
+
+--- the state of the neighbour entry. \verb|nud| is an abbreviation for ``Neighbour
+Unreachability Detection''. The state can take one of the following values:
+
+\begin{enumerate}
+\item \verb|permanent| --- the neighbour entry is valid forever and can be only be removed
+administratively.
+\item \verb|noarp| --- the neighbour entry is valid. No attempts to validate
+this entry will be made but it can be removed when its lifetime expires.
+\item \verb|reachable| --- the neighbour entry is valid until the reachability
+timeout expires.
+\item \verb|stale| --- the neighbour entry is valid but suspicious.
+This option to \verb|ip neigh| does not change the neighbour state if
+it was valid and the address is not changed by this command.
+\end{enumerate}
+
+\end{itemize}
+
+\paragraph{Examples:}
+\begin{itemize}
+\item \verb|ip neigh add 10.0.0.3 lladdr 0:0:0:0:0:1 dev eth0 nud perm|
+
+--- add a permanent ARP entry for the neighbour 10.0.0.3 on the device \verb|eth0|.
+
+\item \verb|ip neigh chg 10.0.0.3 dev eth0 nud reachable|
+
+--- change its state to \verb|reachable|.
+\end{itemize}
+
+
+\subsection{{\tt ip neighbour delete} --- delete a neighbour entry}
+
+\paragraph{Abbreviations:} \verb|delete|, \verb|del|, \verb|d|.
+
+\paragraph{Description:} This command invalidates a neighbour entry.
+
+\paragraph{Arguments:} The arguments are the same as with \verb|ip neigh add|,
+except that \verb|lladdr| and \verb|nud| are ignored.
+
+
+\paragraph{Example:}
+\begin{itemize}
+\item \verb|ip neigh del 10.0.0.3 dev eth0|
+
+--- invalidate an ARP entry for the neighbour 10.0.0.3 on the device \verb|eth0|.
+
+\end{itemize}
+
+\begin{NB}
+ The deleted neighbour entry will not disappear from the tables
+ immediately. If it is in use it cannot be deleted until the last
+ client releases it. Otherwise it will be destroyed during
+ the next garbage collection.
+\end{NB}
+
+
+\paragraph{Warning:} Attempts to delete or manually change
+a \verb|noarp| entry created by the kernel may result in unpredictable behaviour.
+Particularly, the kernel may try to resolve this address even
+on a \verb|NOARP| interface or if the address is multicast or broadcast.
+
+
+\subsection{{\tt ip neighbour show} --- list neighbour entries}
+
+\paragraph{Abbreviations:} \verb|show|, \verb|list|, \verb|sh|, \verb|ls|.
+
+\paragraph{Description:}This commands displays neighbour tables.
+
+\paragraph{Arguments:}
+
+\begin{itemize}
+
+\item \verb|to ADDRESS| (default)
+
+--- the prefix selecting the neighbours to list.
+
+\item \verb|dev NAME|
+
+--- only list the neighbours attached to this device.
+
+\item \verb|unused|
+
+--- only list neighbours which are not currently in use.
+
+\item \verb|nud NUD_STATE|
+
+--- only list neighbour entries in this state. \verb|NUD_STATE| takes
+values listed below or the special value \verb|all| which means all states.
+This option may occur more than once. If this option is absent, \verb|ip|
+lists all entries except for \verb|none| and \verb|noarp|.
+
+\end{itemize}
+
+
+\paragraph{Output format:}
+
+\begin{verbatim}
+kuznet@alisa:~ $ ip neigh ls
+:: dev lo lladdr 00:00:00:00:00:00 nud noarp
+fe80::200:cff:fe76:3f85 dev eth0 lladdr 00:00:0c:76:3f:85 router \
+    nud stale
+0.0.0.0 dev lo lladdr 00:00:00:00:00:00 nud noarp
+193.233.7.254 dev eth0 lladdr 00:00:0c:76:3f:85 nud reachable
+193.233.7.85 dev eth0 lladdr 00:e0:1e:63:39:00 nud stale
+kuznet@alisa:~ $ 
+\end{verbatim}
+
+The first word of each line is the protocol address of the neighbour.
+Then the device name follows. The rest of the line describes the contents of
+the neighbour entry identified by the pair (device, address).
+
+\verb|lladdr| is the link layer address of the neighbour.
+
+\verb|nud| is the state of the ``neighbour unreachability detection'' machine
+for this entry. The detailed description of the neighbour
+state machine can be found in~\cite{RFC-NDISC}. Here is the full list
+of the states with short descriptions:
+
+\begin{enumerate}
+\item\verb|none| --- the state of the neighbour is void.
+\item\verb|incomplete| --- the neighbour is in the process of resolution.
+\item\verb|reachable| --- the neighbour is valid and apparently reachable.
+\item\verb|stale| --- the neighbour is valid, but is probably already
+unreachable, so the kernel will try to check it at the first transmission.
+\item\verb|delay| --- a packet has been sent to the stale neighbour and the kernel is waiting
+for confirmation.
+\item\verb|probe| --- the delay timer expired but no confirmation was received.
+The kernel has started to probe the neighbour with ARP/NDISC messages.
+\item\verb|failed| --- resolution has failed.
+\item\verb|noarp| --- the neighbour is valid. No attempts to check the entry
+will be made.
+\item\verb|permanent| --- it is a \verb|noarp| entry, but only the administrator
+may remove the entry from the neighbour table.
+\end{enumerate}
+
+The link layer address is valid in all states except for \verb|none|,
+\verb|failed| and \verb|incomplete|.
+
+IPv6 neighbours can be marked with the additional flag \verb|router|
+which means that the neighbour introduced itself as an IPv6 router~\cite{RFC-NDISC}.
+
+\paragraph{Statistics:} The \verb|-statistics| option displays some usage
+statistics, f.e.\
+
+\begin{verbatim}
+kuznet@alisa:~ $ ip -s n ls 193.233.7.254
+193.233.7.254 dev eth0 lladdr 00:00:0c:76:3f:85 ref 5 used 12/13/20 \
+    nud reachable
+kuznet@alisa:~ $ 
+\end{verbatim}
+
+Here \verb|ref| is the number of users of this entry
+and \verb|used| is a triplet of time intervals in seconds
+separated by slashes. In this case they show that:
+
+\begin{enumerate}
+\item the entry was used 12 seconds ago.
+\item the entry was confirmed 13 seconds ago.
+\item the entry was updated 20 seconds ago.
+\end{enumerate}
+
+\subsection{{\tt ip neighbour flush} --- flush neighbour entries}
+
+\paragraph{Abbreviations:} \verb|flush|, \verb|f|.
+
+\paragraph{Description:}This command flushes neighbour tables, selecting
+entries to flush by some criteria.
+
+\paragraph{Arguments:} This command has the same arguments as \verb|show|.
+The differences are that it does not run when no arguments are given,
+and that the default neighbour states to be flushed do not include
+\verb|permanent| and \verb|noarp|.
+
+
+\paragraph{Statistics:} With the \verb|-statistics| option, the command
+becomes verbose. It prints out the number of deleted neighbours and the number
+of rounds made to flush the neighbour table. If the option is given
+twice, \verb|ip neigh flush| also dumps all the deleted neighbours
+in the format described in the previous subsection.
+
+\paragraph{Example:}
+\begin{verbatim}
+netadm@alisa:~ # ip -s -s n f 193.233.7.254
+193.233.7.254 dev eth0 lladdr 00:00:0c:76:3f:85 ref 5 used 12/13/20 \
+    nud reachable
+
+*** Round 1, deleting 1 entries ***
+*** Flush is complete after 1 round ***
+netadm@alisa:~ # 
+\end{verbatim}
+
+
+\section{{\tt ip route} --- routing table management}
+\label{IP-ROUTE}
+
+\paragraph{Abbreviations:} \verb|route|, \verb|ro|, \verb|r|.
+
+\paragraph{Object:} \verb|route| entries in the kernel routing tables keep
+information about paths to other networked nodes.
+
+Each route entry has a {\em key\/} consisting of a {\em prefix\/}
+(i.e.\ a pair containing a network address and the length of its mask) and,
+optionally, the TOS value. An IP packet matches the route if the highest
+bits of its destination address are equal to the route prefix at least
+up to the prefix length and if the TOS of the route is zero or equal to
+the TOS of the packet.
+ 
+If several routes match the packet, the following pruning rules
+are used to select the best one (see~\cite{RFC1812}):
+\begin{enumerate}
+\item The longest matching prefix is selected. All shorter ones
+are dropped.
+
+\item If the TOS of some route with the longest prefix is equal to the TOS
+of the packet, the routes with different TOS are dropped.
+
+If no exact TOS match was found and routes with TOS=0 exist,
+the rest of routes are pruned.
+
+Otherwise, the route lookup fails.
+
+\item If several routes remain after the previous steps, then
+the routes with the best preference values are selected.
+
+\item If we still have several routes, then the {\em first\/} of them
+is selected.
+
+\begin{NB}
+ Note the ambiguity of the last step. Unfortunately, Linux
+ historically allows such a bizarre situation. The sense of the
+word ``first'' depends on the order of route additions and it is practically
+impossible to maintain a bundle of such routes in this order.
+\end{NB}
+
+For simplicity we will limit ourselves to the case where such a situation
+is impossible and routes are uniquely identified by the triplet
+\{prefix, tos, preference\}. Actually, it is impossible to create
+non-unique routes with \verb|ip| commands described in this section.
+
+One useful exception to this rule is the default route on non-forwarding
+hosts. It is ``officially'' allowed to have several fallback routes
+when several routers are present on directly connected networks.
+In this case, Linux-2.2 makes ``dead gateway detection''~\cite{RFC1122}
+controlled by neighbour unreachability detection and by advice
+from transport protocols to select a working router, so the order
+of the routes is not essential. However, in this case,
+fiddling with default routes manually is not recommended. Use the Router Discovery
+protocol (see Appendix~\ref{EXAMPLE-SETUP}, p.\pageref{EXAMPLE-SETUP})
+instead. Actually, Linux-2.2 IPv6 does not give user level applications
+any access to default routes.
+\end{enumerate}
+
+Certainly, the steps above are not performed exactly
+in this sequence. Instead, the routing table in the kernel is kept
+in some data structure to achieve the final result
+with minimal cost. However, not depending on a particular
+routing algorithm implemented in the kernel, we can summarize
+the statements above as: a route is identified by the triplet
+\{prefix, tos, preference\}. This {\em key\/} lets us locate
+the route in the routing table.
+
+\paragraph{Route attributes:} Each route key refers to a routing
+information record containing
+the data required to deliver IP packets (f.e.\ output device and
+next hop router) and some optional attributes (f.e. the path MTU or
+the preferred source address when communicating with this destination).
+These attributes are described in the following subsection.
+
+\paragraph{Route types:} \label{IP-ROUTE-TYPES}
+It is important that the set
+of required and optional attributes depend on the route {\em type\/}.
+The most important route type
+is \verb|unicast|. It describes real paths to other hosts.
+As a rule, common routing tables contain only such routes. However,
+there are other types of routes with different semantics. The
+full list of types understood by Linux-2.2 is:
+\begin{itemize}
+\item \verb|unicast| --- the route entry describes real paths to the
+destinations covered by the route prefix.
+\item \verb|unreachable| --- these destinations are unreachable. Packets
+are discarded and the ICMP message {\em host unreachable\/} is generated.
+The local senders get an \verb|EHOSTUNREACH| error.
+\item \verb|blackhole| --- these destinations are unreachable. Packets
+are discarded silently. The local senders get an \verb|EINVAL| error.
+\item \verb|prohibit| --- these destinations are unreachable. Packets
+are discarded and the ICMP message {\em communication administratively
+prohibited\/} is generated. The local senders get an \verb|EACCES| error.
+\item \verb|local| --- the destinations are assigned to this
+host. The packets are looped back and delivered locally.
+\item \verb|broadcast| --- the destinations are broadcast addresses.
+The packets are sent as link broadcasts.
+\item \verb|throw| --- a special control route used together with policy
+rules (see sec.\ref{IP-RULE}, p.\pageref{IP-RULE}). If such a route is selected, lookup
+in this table is terminated pretending that no route was found.
+Without policy routing it is equivalent to the absence of the route in the routing
+table. The packets are dropped and the ICMP message {\em net unreachable\/}
+is generated. The local senders get an \verb|ENETUNREACH| error.
+\item \verb|nat| --- a special NAT route. Destinations covered by the prefix
+are considered to be dummy (or external) addresses which require translation
+to real (or internal) ones before forwarding. The addresses to translate to
+are selected with the attribute \verb|via|. More about NAT is
+in Appendix~\ref{ROUTE-NAT}, p.\pageref{ROUTE-NAT}.
+\item \verb|anycast| --- ({\em not implemented\/}) the destinations are
+{\em anycast\/} addresses assigned to this host. They are mainly equivalent
+to \verb|local| with one difference: such addresses are invalid when used
+as the source address of any packet.
+\item \verb|multicast| --- a special type used for multicast routing.
+It is not present in normal routing tables.
+\end{itemize}
+
+\paragraph{Route tables:} Linux-2.2 can pack routes into several routing
+tables identified by a number in the range from 1 to 255 or by
+name from the file \verb|/etc/iproute2/rt_tables|. By default all normal
+routes are inserted into the \verb|main| table (ID 254) and the kernel only uses
+this table when calculating routes.
+
+Actually, one other table always exists, which is invisible but
+even more important. It is the \verb|local| table (ID 255). This table
+consists of routes for local and broadcast addresses. The kernel maintains
+this table automatically and the administrator usually need not modify it
+or even look at it.
+
+The multiple routing tables enter the game when {\em policy routing\/}
+is used. See sec.\ref{IP-RULE}, p.\pageref{IP-RULE}.
+In this case, the table identifier effectively becomes
+one more parameter, which should be added to the triplet
+\{prefix, tos, preference\} to uniquely identify the route.
+
+
+\subsection{{\tt ip route add} --- add a new route\\
+	{\tt ip route change} --- change a route\\
+	{\tt ip route replace} --- change a route or add a new one}
+\label{IP-ROUTE-ADD}
+
+\paragraph{Abbreviations:} \verb|add|, \verb|a|; \verb|change|, \verb|chg|;
+	\verb|replace|, \verb|repl|.
+
+
+\paragraph{Arguments:}
+\begin{itemize}
+\item \verb|to PREFIX| or \verb|to TYPE PREFIX| (default)
+
+--- the destination prefix of the route. If \verb|TYPE| is omitted,
+\verb|ip| assumes type \verb|unicast|. Other values of \verb|TYPE|
+are listed above. \verb|PREFIX| is an IP or IPv6 address optionally followed
+by a slash and the prefix length. If the length of the prefix is missing,
+\verb|ip| assumes a full-length host route. There is also a special
+\verb|PREFIX| --- \verb|default| --- which is equivalent to IP \verb|0/0| or
+to IPv6 \verb|::/0|.
+
+\item \verb|tos TOS| or \verb|dsfield TOS|
+
+--- the Type Of Service (TOS) key. This key has no associated mask and
+the longest match is understood as: First, compare the TOS
+of the route and of the packet. If they are not equal, then the packet
+may still match a route with a zero TOS. \verb|TOS| is either an 8 bit hexadecimal
+number or an identifier from {\tt /etc/iproute2/rt\_dsfield}.
+
+
+\item \verb|metric NUMBER| or \verb|preference NUMBER|
+
+--- the preference value of the route. \verb|NUMBER| is an arbitrary 32bit number.
+
+\item \verb|table TABLEID|
+
+--- the table to add this route to.
+\verb|TABLEID| may be a number or a string from the file
+\verb|/etc/iproute2/rt_tables|. If this parameter is omitted,
+\verb|ip| assumes the \verb|main| table, with the exception of
+\verb|local|, \verb|broadcast| and \verb|nat| routes, which are
+put into the \verb|local| table by default.
+
+\item \verb|dev NAME|
+
+--- the output device name.
+
+\item \verb|via ADDRESS|
+
+--- the address of the nexthop router. Actually, the sense of this field depends
+on the route type. For normal \verb|unicast| routes it is either the true nexthop
+router or, if it is a direct route installed in BSD compatibility mode,
+it can be a local address of the interface.
+For NAT routes it is the first address of the block of translated IP destinations.
+
+\item \verb|src ADDRESS|
+
+--- the source address to prefer when sending to the destinations
+covered by the route prefix.
+
+\item \verb|realm REALMID|
+
+--- the realm to which this route is assigned.
+\verb|REALMID| may be a number or a string from the file
+\verb|/etc/iproute2/rt_realms|. Sec.\ref{RT-REALMS} (p.\pageref{RT-REALMS})
+contains more information on realms.
+
+\item \verb|mtu MTU| or \verb|mtu lock MTU|
+
+--- the MTU along the path to the destination. If the modifier \verb|lock| is
+not used, the MTU may be updated by the kernel due to Path MTU Discovery.
+If the modifier \verb|lock| is used, no path MTU discovery will be tried,
+all packets will be sent without the DF bit in IPv4 case
+or fragmented to MTU for IPv6.
+
+\item \verb|window NUMBER|
+
+--- the maximal window for TCP to advertise to these destinations,
+measured in bytes. It limits maximal data bursts that our TCP
+peers are allowed to send to us.
+
+\item \verb|rtt NUMBER|
+
+--- the initial RTT (``Round Trip Time'') estimate.
+
+
+\item \verb|rttvar NUMBER|
+
+--- \threeonly the initial RTT variance estimate.
+
+
+\item \verb|ssthresh NUMBER|
+
+--- \threeonly an estimate for the initial slow start threshold.
+
+
+\item \verb|cwnd NUMBER|
+
+--- \threeonly the clamp for congestion window. It is ignored if the \verb|lock|
+    flag is not used.
+
+
+\item \verb|advmss NUMBER|
+
+--- \threeonly the MSS (``Maximal Segment Size'') to advertise to these
+    destinations when establishing TCP connections. If it is not given,
+    Linux uses a default value calculated from the first hop device MTU.
+
+\begin{NB}
+  If the path to these destination is asymmetric, this guess may be wrong.
+\end{NB}
+
+\item \verb|reordering NUMBER|
+
+--- \threeonly Maximal reordering on the path to this destination.
+    If it is not given, Linux uses the value selected with \verb|sysctl|
+    variable \verb|net/ipv4/tcp_reordering|.
+
+\item \verb|hoplimit NUMBER|
+
+--- [2.5.74+ only] Maximum number of hops on the path to this destination.
+    The default is the value selected with the \verb|sysctl| variable
+    \verb|net/ipv4/ip_default_ttl|.
+
+\item \verb|initcwnd NUMBER|
+--- [2.5.70+ only] Initial congestion window size for connections to
+    this destination. Actual window size is this value multiplied by the
+    MSS (``Maximal Segment Size'') for same connection. The default is
+    zero, meaning to use the values specified in~\cite{RFC2414}.
+
++\item \verb|initrwnd NUMBER|
+ 
++--- [2.6.33+ only] Initial receive window size for connections to 
++    this destination. The actual window size is this value multiplied
++    by the MSS (''Maximal Segment Size'') of the connection. The default
++    value is zero, meaning to use Slow Start value.
+ 
+\item \verb|nexthop NEXTHOP|
+
+--- the nexthop of a multipath route. \verb|NEXTHOP| is a complex value
+with its own syntax similar to the top level argument lists:
+\begin{itemize}
+\item \verb|via ADDRESS| is the nexthop router.
+\item \verb|dev NAME| is the output device.
+\item \verb|weight NUMBER| is a weight for this element of a multipath
+route reflecting its relative bandwidth or quality.
+\end{itemize}
+
+\item \verb|scope SCOPE_VAL|
+
+--- the scope of the destinations covered by the route prefix.
+\verb|SCOPE_VAL| may be a number or a string from the file
+\verb|/etc/iproute2/rt_scopes|.
+If this parameter is omitted,
+\verb|ip| assumes scope \verb|global| for all gatewayed \verb|unicast|
+routes, scope \verb|link| for direct \verb|unicast| and \verb|broadcast| routes
+and scope \verb|host| for \verb|local| routes.
+
+\item \verb|protocol RTPROTO|
+
+--- the routing protocol identifier of this route.
+\verb|RTPROTO| may be a number or a string from the file
+\verb|/etc/iproute2/rt_protos|. If the routing protocol ID is
+not given, \verb|ip| assumes protocol \verb|boot| (i.e.\
+it assumes the route was added by someone who doesn't
+understand what they are doing). Several protocol values have a fixed interpretation.
+Namely:
+\begin{itemize}
+\item \verb|redirect| --- the route was installed due to an ICMP redirect.
+\item \verb|kernel| --- the route was installed by the kernel during
+autoconfiguration.
+\item \verb|boot| --- the route was installed during the bootup sequence.
+If a routing daemon starts, it will purge all of them.
+\item \verb|static| --- the route was installed by the administrator
+to override dynamic routing. Routing daemon will respect them
+and, probably, even advertise them to its peers.
+\item \verb|ra| --- the route was installed by Router Discovery protocol.
+\end{itemize}
+The rest of the values are not reserved and the administrator is free
+to assign (or not to assign) protocol tags. At least, routing
+daemons should take care of setting some unique protocol values,
+f.e.\ as they are assigned in \verb|rtnetlink.h| or in \verb|rt_protos|
+database.
+
+
+\item \verb|onlink|
+
+--- pretend that the nexthop is directly attached to this link,
+even if it does not match any interface prefix. One application of this
+option may be found in~\cite{IP-TUNNELS}.
+
+\item \verb|pref PREF|
+
+--- the IPv6 route preference.
+\verb|PREF| PREF is a string specifying the route preference as defined in
+RFC4191 for Router Discovery messages. Namely:
+\begin{itemize}
+\item \verb|low| --- the route has a lowest priority.
+\item \verb|medium| --- the route has a default priority.
+\item \verb|high| --- the route has a highest priority.
+\end{itemize}
+
+\end{itemize}
+
+
+\begin{NB}
+  Actually there are more commands: \verb|prepend| does the same
+  thing as classic \verb|route add|, i.e.\ adds a route, even if another
+  route to the same destination exists. Its opposite case is \verb|append|,
+  which adds the route to the end of the list. Avoid these
+  features.
+\end{NB}
+\begin{NB}
+  More sad news, IPv6 only understands the \verb|append| command correctly.
+  All the others are translated into \verb|append| commands. Certainly,
+  this will change in the future.
+\end{NB}
+
+\paragraph{Examples:}
+\begin{itemize}
+\item add a plain route to network 10.0.0/24 via gateway 193.233.7.65
+\begin{verbatim}
+  ip route add 10.0.0/24 via 193.233.7.65
+\end{verbatim}
+\item change it to a direct route via the \verb|dummy| device
+\begin{verbatim}
+  ip ro chg 10.0.0/24 dev dummy
+\end{verbatim}
+\item add a default multipath route splitting the load between \verb|ppp0|
+and \verb|ppp1|
+\begin{verbatim}
+  ip route add default scope global nexthop dev ppp0 \
+                                    nexthop dev ppp1
+\end{verbatim}
+Note the scope value. It is not necessary but it informs the kernel
+that this route is gatewayed rather than direct. Actually, if you
+know the addresses of remote endpoints it would be better to use the
+\verb|via| parameter.
+\item announce that the address 192.203.80.144 is not a real one, but
+should be translated to 193.233.7.83 before forwarding
+\begin{verbatim}
+  ip route add nat 192.203.80.144 via 193.233.7.83
+\end{verbatim}
+Backward translation is setup with policy rules described
+in the following section (sec.\ref{IP-RULE}, p.\pageref{IP-RULE}).
+\end{itemize}
+
+\subsection{{\tt ip route delete} --- delete a route}
+
+\paragraph{Abbreviations:} \verb|delete|, \verb|del|, \verb|d|.
+
+\paragraph{Arguments:} \verb|ip route del| has the same arguments as
+\verb|ip route add|, but their semantics are a bit different.
+
+Key values (\verb|to|, \verb|tos|, \verb|preference| and \verb|table|)
+select the route to delete. If optional attributes are present, \verb|ip|
+verifies that they coincide with the attributes of the route to delete.
+If no route with the given key and attributes was found, \verb|ip route del|
+fails.
+\begin{NB}
+Linux-2.0 had the option to delete a route selected only by prefix address,
+ignoring its length (i.e.\ netmask). This option no longer exists
+because it was ambiguous. However, look at {\tt ip route flush}
+(sec.\ref{IP-ROUTE-FLUSH}, p.\pageref{IP-ROUTE-FLUSH}) which
+provides similar and even richer functionality.
+\end{NB}
+
+\paragraph{Example:}
+\begin{itemize}
+\item delete the multipath route created by the command in previous subsection
+\begin{verbatim}
+  ip route del default scope global nexthop dev ppp0 \
+                                    nexthop dev ppp1
+\end{verbatim}
+\end{itemize}
+
+
+
+\subsection{{\tt ip route show} --- list routes}
+
+\paragraph{Abbreviations:} \verb|show|, \verb|list|, \verb|sh|, \verb|ls|, \verb|l|.
+
+\paragraph{Description:} the command displays the contents of the routing tables
+or the route(s) selected by some criteria.
+
+
+\paragraph{Arguments:}
+\begin{itemize}
+\item \verb|to SELECTOR| (default)
+
+--- only select routes from the given range of destinations. \verb|SELECTOR|
+consists of an optional modifier (\verb|root|, \verb|match| or \verb|exact|)
+and a prefix. \verb|root PREFIX| selects routes with prefixes not shorter
+than \verb|PREFIX|. F.e.\ \verb|root 0/0| selects the entire routing table.
+\verb|match PREFIX| selects routes with prefixes not longer than
+\verb|PREFIX|. F.e.\ \verb|match 10.0/16| selects \verb|10.0/16|,
+\verb|10/8| and \verb|0/0|, but it does not select \verb|10.1/16| and
+\verb|10.0.0/24|. And \verb|exact PREFIX| (or just \verb|PREFIX|)
+selects routes with this exact prefix. If neither of these options
+are present, \verb|ip| assumes \verb|root 0/0| i.e.\ it lists the entire table.
+
+
+\item \verb|tos TOS| or \verb|dsfield TOS|
+
+ --- only select routes with the given TOS.
+
+
+\item \verb|table TABLEID|
+
+ --- show the routes from this table(s). The default setting is to show
+\verb|table| \verb|main|. \verb|TABLEID| may either be the ID of a real table
+or one of the special values:
+  \begin{itemize}
+  \item \verb|all| --- list all of the tables.
+  \item \verb|cache| --- dump the routing cache.
+  \end{itemize}
+\begin{NB}
+  IPv6 has a single table. However, splitting it into \verb|main|, \verb|local|
+  and \verb|cache| is emulated by the \verb|ip| utility.
+\end{NB}
+
+\item \verb|cloned| or \verb|cached|
+
+--- list cloned routes i.e.\ routes which were dynamically forked from
+other routes because some route attribute (f.e.\ MTU) was updated.
+Actually, it is equivalent to \verb|table cache|.
+
+\item \verb|from SELECTOR|
+
+--- the same syntax as for \verb|to|, but it binds the source address range
+rather than destinations. Note that the \verb|from| option only works with
+cloned routes.
+
+\item \verb|protocol RTPROTO|
+
+--- only list routes of this protocol.
+
+
+\item \verb|scope SCOPE_VAL|
+
+--- only list routes with this scope.
+
+\item \verb|type TYPE|
+
+--- only list routes of this type.
+
+\item \verb|dev NAME|
+
+--- only list routes going via this device.
+
+\item \verb|via PREFIX|
+
+--- only list routes going via the nexthop routers selected by \verb|PREFIX|.
+
+\item \verb|src PREFIX|
+
+--- only list routes with preferred source addresses selected
+by \verb|PREFIX|.
+
+\item \verb|realm REALMID| or \verb|realms FROMREALM/TOREALM|
+
+--- only list routes with these realms.
+
+\end{itemize}
+
+\paragraph{Examples:} Let us count routes of protocol \verb|gated/bgp|
+on a router:
+\begin{verbatim}
+kuznet@amber:~ $ ip ro ls proto gated/bgp | wc
+   1413    9891    79010
+kuznet@amber:~ $
+\end{verbatim}
+To count the size of the routing cache, we have to use the \verb|-o| option
+because cached attributes can take more than one line of output:
+\begin{verbatim}
+kuznet@amber:~ $ ip -o ro ls cloned | wc
+   159    2543    18707
+kuznet@amber:~ $
+\end{verbatim}
+
+
+\paragraph{Output format:} The output of this command consists
+of per route records separated by line feeds.
+However, some records may consist
+of more than one line: particularly, this is the case when the route
+is cloned or you requested additional statistics. If the
+\verb|-o| option was given, then line feeds separating lines inside
+records are replaced with the backslash sign.
+
+The output has the same syntax as arguments given to {\tt ip route add},
+so that it can be understood easily. F.e.\
+\begin{verbatim}
+kuznet@amber:~ $ ip ro ls 193.233.7/24
+193.233.7.0/24 dev eth0  proto gated/conn  scope link \
+    src 193.233.7.65 realms inr.ac 
+kuznet@amber:~ $
+\end{verbatim}
+
+If you list cloned entries, the output contains other attributes which
+are evaluated during route calculation and updated during route
+lifetime. An example of the output is:
+\begin{verbatim}
+kuznet@amber:~ $ ip ro ls 193.233.7.82 tab cache
+193.233.7.82 from 193.233.7.82 dev eth0  src 193.233.7.65 \
+  realms inr.ac/inr.ac 
+    cache <src-direct,redirect>  mtu 1500 rtt 300 iif eth0
+193.233.7.82 dev eth0  src 193.233.7.65 realms inr.ac 
+    cache  mtu 1500 rtt 300
+kuznet@amber:~ $
+\end{verbatim}
+\begin{NB}
+  \label{NB-strange-route}
+  The route looks a bit strange, doesn't it? Did you notice that
+  it is a path from 193.233.7.82 back to 193.233.82? Well, you will
+  see in the section on \verb|ip route get| (p.\pageref{NB-nature-of-strangeness})
+  how it appeared.
+\end{NB}
+The second line, starting with the word \verb|cache|, shows
+additional attributes which normal routes do not possess.
+Cached flags are summarized in angle brackets:
+\begin{itemize}
+\item \verb|local| --- packets are delivered locally.
+It stands for loopback unicast routes, for broadcast routes
+and for multicast routes, if this host is a member of the corresponding
+group.
+
+\item \verb|reject| --- the path is bad. Any attempt to use it results
+in an error. See attribute \verb|error| below (p.\pageref{IP-ROUTE-GET-error}).
+
+\item \verb|mc| --- the destination is multicast.
+
+\item \verb|brd| --- the destination is broadcast.
+
+\item \verb|src-direct| --- the source is on a directly connected
+interface.
+
+\item \verb|redirected| --- the route was created by an ICMP Redirect.
+
+\item \verb|redirect| --- packets going via this route will 
+trigger an ICMP redirect.
+
+\item \verb|fastroute| --- the route is eligible to be used for fastroute.
+
+\item \verb|equalize| --- make packet by packet randomization
+along this path.
+
+\item \verb|dst-nat| --- the destination address requires translation.
+
+\item \verb|src-nat| --- the source address requires translation.
+
+\item \verb|masq| --- the source address requires masquerading.
+This feature disappeared in linux-2.4.
+
+\item \verb|notify| --- ({\em not implemented}) change/deletion
+of this route will trigger RTNETLINK notification.
+\end{itemize}
+
+Then some optional attributes follow:
+\begin{itemize}
+\item \verb|error| --- on \verb|reject| routes it is error code
+returned to local senders when they try to use this route.
+These error codes are translated into ICMP error codes, sent to remote
+senders, according to the rules described above in the subsection
+devoted to route types (p.\pageref{IP-ROUTE-TYPES}).
+\label{IP-ROUTE-GET-error}
+
+\item \verb|expires| --- this entry will expire after this timeout.
+
+\item \verb|iif| --- the packets for this path are expected to arrive
+on this interface.
+\end{itemize}
+
+\paragraph{Statistics:} With the \verb|-statistics| option, more
+information about this route is shown:
+\begin{itemize}
+\item \verb|users| --- the number of users of this entry.
+\item \verb|age| --- shows when this route was last used.
+\item \verb|used| --- the number of lookups of this route since its creation.
+\end{itemize}
+
+\subsection{{\tt ip route save} -- save routing tables}
+\label{IP-ROUTE-SAVE}
+
+\paragraph{Description:} this command saves the contents of the routing
+tables or the route(s) selected by some criteria to standard output.
+
+\paragraph{Arguments:} \verb|ip route save| has the same arguments as
+\verb|ip route show|.
+
+\paragraph{Example:} This saves all the routes to the {\tt saved\_routes}
+file:
+\begin{verbatim}
+dan@caffeine:~ # ip route save > saved_routes
+\end{verbatim}
+
+\paragraph{Output format:} The format of the data stream provided by
+\verb|ip route save| is that of \verb|rtnetlink|.  See
+\verb|rtnetlink(7)| for more information.
+
+\subsection{{\tt ip route restore} -- restore routing tables}
+\label{IP-ROUTE-RESTORE}
+
+\paragraph{Description:} this command restores the contents of the routing
+tables according to a data stream as provided by \verb|ip route save| via
+standard input.  Note that any routes already in the table are left unchanged.
+Any routes in the input stream that already exist in the tables are ignored.
+
+\paragraph{Arguments:} This command takes no arguments.
+
+\paragraph{Example:} This restores all routes that were saved to the
+{\tt saved\_routes} file:
+
+\begin{verbatim}
+dan@caffeine:~ # ip route restore < saved_routes
+\end{verbatim}
+
+\subsection{{\tt ip route flush} --- flush routing tables}
+\label{IP-ROUTE-FLUSH}
+
+\paragraph{Abbreviations:} \verb|flush|, \verb|f|.
+
+\paragraph{Description:} this command flushes routes selected
+by some criteria.
+
+\paragraph{Arguments:} the arguments have the same syntax and semantics
+as the arguments of \verb|ip route show|, but routing tables are not
+listed but purged. The only difference is the default action: \verb|show|
+dumps all the IP main routing table but \verb|flush| prints the helper page.
+The reason for this difference does not require any explanation, does it?
+
+
+\paragraph{Statistics:} With the \verb|-statistics| option, the command
+becomes verbose. It prints out the number of deleted routes and the number
+of rounds made to flush the routing table. If the option is given
+twice, \verb|ip route flush| also dumps all the deleted routes
+in the format described in the previous subsection.
+
+\paragraph{Examples:} The first example flushes all the
+gatewayed routes from the main table (f.e.\ after a routing daemon crash).
+\begin{verbatim}
+netadm@amber:~ # ip -4 ro flush scope global type unicast
+\end{verbatim}
+This option deserves to be put into a scriptlet \verb|routef|.
+\begin{NB}
+This option was described in the \verb|route(8)| man page borrowed
+from BSD, but was never implemented in Linux.
+\end{NB}
+
+The second example flushes all IPv6 cloned routes:
+\begin{verbatim}
+netadm@amber:~ # ip -6 -s -s ro flush cache
+3ffe:2400::220:afff:fef4:c5d1 via 3ffe:2400::220:afff:fef4:c5d1 \
+  dev eth0  metric 0 
+    cache  used 2 age 12sec mtu 1500 rtt 300
+3ffe:2400::280:adff:feb7:8034 via 3ffe:2400::280:adff:feb7:8034 \
+  dev eth0  metric 0 
+    cache  used 2 age 15sec mtu 1500 rtt 300
+3ffe:2400::280:c8ff:fe59:5bcc via 3ffe:2400::280:c8ff:fe59:5bcc \
+  dev eth0  metric 0 
+    cache  users 1 used 1 age 23sec mtu 1500 rtt 300
+3ffe:2400:0:1:2a0:ccff:fe66:1878 via 3ffe:2400:0:1:2a0:ccff:fe66:1878 \
+  dev eth1  metric 0 
+    cache  used 2 age 20sec mtu 1500 rtt 300
+3ffe:2400:0:1:a00:20ff:fe71:fb30 via 3ffe:2400:0:1:a00:20ff:fe71:fb30 \
+  dev eth1  metric 0 
+    cache  used 2 age 33sec mtu 1500 rtt 300
+ff02::1 via ff02::1 dev eth1  metric 0 
+    cache  users 1 used 1 age 45sec mtu 1500 rtt 300
+
+*** Round 1, deleting 6 entries ***
+*** Flush is complete after 1 round ***
+netadm@amber:~ # ip -6 -s -s ro flush cache
+Nothing to flush.
+netadm@amber:~ #
+\end{verbatim}
+
+The third example flushes BGP routing tables after a \verb|gated|
+death.
+\begin{verbatim}
+netadm@amber:~ # ip ro ls proto gated/bgp | wc
+   1408    9856    78730
+netadm@amber:~ # ip -s ro f proto gated/bgp
+
+*** Round 1, deleting 1408 entries ***
+*** Flush is complete after 1 round ***
+netadm@amber:~ # ip ro f proto gated/bgp
+Nothing to flush.
+netadm@amber:~ # ip ro ls proto gated/bgp
+netadm@amber:~ #
+\end{verbatim}
+
+
+\subsection{{\tt ip route get} --- get a single route}
+\label{IP-ROUTE-GET}
+
+\paragraph{Abbreviations:} \verb|get|, \verb|g|.
+
+\paragraph{Description:} this command gets a single route to a destination
+and prints its contents exactly as the kernel sees it.
+
+\paragraph{Arguments:} 
+\begin{itemize}
+\item \verb|to ADDRESS| (default)
+
+--- the destination address.
+
+\item \verb|from ADDRESS|
+
+--- the source address.
+
+\item \verb|tos TOS| or \verb|dsfield TOS|
+
+--- the Type Of Service.
+
+\item \verb|iif NAME|
+
+--- the device from which this packet is expected to arrive.
+
+\item \verb|oif NAME|
+
+--- force the output device on which this packet will be routed.
+
+\item \verb|connected|
+
+--- if no source address (option \verb|from|) was given, relookup
+the route with the source set to the preferred address received from the first lookup.
+If policy routing is used, it may be a different route.
+
+\end{itemize}
+
+Note that this operation is not equivalent to \verb|ip route show|.
+\verb|show| shows existing routes. \verb|get| resolves them and
+creates new clones if necessary. Essentially, \verb|get|
+is equivalent to sending a packet along this path.
+If the \verb|iif| argument is not given, the kernel creates a route
+to output packets towards the requested destination.
+This is equivalent to pinging the destination
+with a subsequent {\tt ip route ls cache}, however, no packets are
+actually sent. With the \verb|iif| argument, the kernel pretends
+that a packet arrived from this interface and searches for
+a path to forward the packet.
+
+\paragraph{Output format:} This command outputs routes in the same
+format as \verb|ip route ls|.
+
+\paragraph{Examples:} 
+\begin{itemize}
+\item Find a route to output packets to 193.233.7.82:
+\begin{verbatim}
+kuznet@amber:~ $ ip route get 193.233.7.82
+193.233.7.82 dev eth0  src 193.233.7.65 realms inr.ac
+    cache  mtu 1500 rtt 300
+kuznet@amber:~ $
+\end{verbatim}
+
+\item Find a route to forward packets arriving on \verb|eth0|
+from 193.233.7.82 and destined for 193.233.7.82:
+\begin{verbatim}
+kuznet@amber:~ $ ip r g 193.233.7.82 from 193.233.7.82 iif eth0
+193.233.7.82 from 193.233.7.82 dev eth0  src 193.233.7.65 \
+  realms inr.ac/inr.ac 
+    cache <src-direct,redirect>  mtu 1500 rtt 300 iif eth0
+kuznet@amber:~ $
+\end{verbatim}
+\begin{NB}
+  \label{NB-nature-of-strangeness}
+  This is the command that created the funny route from 193.233.7.82
+  looped back to 193.233.7.82 (cf.\ NB on~p.\pageref{NB-strange-route}).
+  Note the \verb|redirect| flag on it.
+\end{NB}
+
+\item Find a multicast route for packets arriving on \verb|eth0|
+from host 193.233.7.82 and destined for multicast group 224.2.127.254
+(it is assumed that a multicast routing daemon is running.
+In this case, it is \verb|pimd|)
+\begin{verbatim}
+kuznet@amber:~ $ ip r g 224.2.127.254 from 193.233.7.82 iif eth0
+multicast 224.2.127.254 from 193.233.7.82 dev lo  \
+  src 193.233.7.65 realms inr.ac/cosmos 
+    cache <mc> iif eth0 Oifs: eth1 pimreg
+kuznet@amber:~ $
+\end{verbatim}
+This route differs from the ones seen before. It contains a ``normal'' part
+and a ``multicast'' part. The normal part is used to deliver (or not to
+deliver) the packet to local IP listeners. In this case the router
+is not a member
+of this group, so that route has no \verb|local| flag and only
+forwards packets. The output device for such entries is always loopback.
+The multicast part consists of an additional \verb|Oifs:| list showing
+the output interfaces.
+\end{itemize}
+
+
+It is time for a more complicated example. Let us add an invalid
+gatewayed route for a destination which is really directly connected:
+\begin{verbatim}
+netadm@alisa:~ # ip route add 193.233.7.98 via 193.233.7.254
+netadm@alisa:~ # ip route get 193.233.7.98
+193.233.7.98 via 193.233.7.254 dev eth0  src 193.233.7.90
+    cache  mtu 1500 rtt 3072
+netadm@alisa:~ #
+\end{verbatim}
+and probe it with ping:
+\begin{verbatim}
+netadm@alisa:~ # ping -n 193.233.7.98
+PING 193.233.7.98 (193.233.7.98) from 193.233.7.90 : 56 data bytes
+From 193.233.7.254: Redirect Host(New nexthop: 193.233.7.98)
+64 bytes from 193.233.7.98: icmp_seq=0 ttl=255 time=3.5 ms
+From 193.233.7.254: Redirect Host(New nexthop: 193.233.7.98)
+64 bytes from 193.233.7.98: icmp_seq=1 ttl=255 time=2.2 ms
+64 bytes from 193.233.7.98: icmp_seq=2 ttl=255 time=0.4 ms
+64 bytes from 193.233.7.98: icmp_seq=3 ttl=255 time=0.4 ms
+64 bytes from 193.233.7.98: icmp_seq=4 ttl=255 time=0.4 ms
+^C
+--- 193.233.7.98 ping statistics ---
+5 packets transmitted, 5 packets received, 0% packet loss
+round-trip min/avg/max = 0.4/1.3/3.5 ms
+netadm@alisa:~ #
+\end{verbatim}
+What happened? Router 193.233.7.254 understood that we have a much
+better path to the destination and sent us an ICMP redirect message.
+We may retry \verb|ip route get| to see what we have in the routing
+tables now:
+\begin{verbatim}
+netadm@alisa:~ # ip route get 193.233.7.98
+193.233.7.98 dev eth0  src 193.233.7.90 
+    cache <redirected>  mtu 1500 rtt 3072
+netadm@alisa:~ #
+\end{verbatim}
+
+
+
+\section{{\tt ip rule} --- routing policy database management}
+\label{IP-RULE}
+
+\paragraph{Abbreviations:} \verb|rule|, \verb|ru|.
+
+\paragraph{Object:} \verb|rule|s in the routing policy database control
+the route selection algorithm.
+
+Classic routing algorithms used in the Internet make routing decisions
+based only on the destination address of packets (and in theory,
+but not in practice, on the TOS field). The seminal review of classic
+routing algorithms and their modifications can be found in~\cite{RFC1812}.
+
+In some circumstances we want to route packets differently depending not only
+on destination addresses, but also on other packet fields: source address,
+IP protocol, transport protocol ports or even packet payload.
+This task is called ``policy routing''.
+
+\begin{NB}
+  ``policy routing'' $\neq$ ``routing policy''.
+
+\noindent	``policy routing'' $=$ ``cunning routing''.
+
+\noindent	``routing policy'' $=$ ``routing tactics'' or ``routing plan''.
+\end{NB}
+
+To solve this task, the conventional destination based routing table, ordered
+according to the longest match rule, is replaced with a ``routing policy
+database'' (or RPDB), which selects routes
+by executing some set of rules. The rules may have lots of keys of different
+natures and therefore they have no natural ordering, but one imposed
+by the administrator. Linux-2.2 RPDB is a linear list of rules
+ordered by numeric priority value.
+RPDB explicitly allows matching a few packet fields:
+
+\begin{itemize}
+\item packet source address.
+\item packet destination address.
+\item TOS.
+\item incoming interface (which is packet metadata, rather than a packet field).
+\end{itemize}
+
+Matching IP protocols and transport ports is also possible,
+indirectly, via \verb|ipchains|, by exploiting their ability
+to mark some classes of packets with \verb|fwmark|. Therefore,
+\verb|fwmark| is also included in the set of keys checked by rules.
+
+Each policy routing rule consists of a {\em selector\/} and an {\em action\/}
+predicate. The RPDB is scanned in the order of increasing priority. The selector
+of each rule is applied to \{source address, destination address, incoming
+interface, tos, fwmark\} and, if the selector matches the packet,
+the action is performed.  The action predicate may return with success.
+In this case, it will either give a route or failure indication
+and the RPDB lookup is terminated. Otherwise, the RPDB program
+continues on the next rule.
+
+What is the action, semantically? The natural action is to select the
+nexthop and the output device. This is what
+Cisco IOS~\cite{IOS} does. Let us call it ``match \& set''.
+The Linux-2.2 approach is more flexible. The action includes
+lookups in destination-based routing tables and selecting
+a route from these tables according to the classic longest match algorithm.
+The ``match \& set'' approach is the simplest case of the Linux one. It is realized
+when a second level routing table contains a single default route.
+Recall that Linux-2.2 supports multiple tables
+managed with the \verb|ip route| command, described in the previous section.
+
+At startup time the kernel configures the default RPDB consisting of three
+rules:
+
+\begin{enumerate}
+\item Priority: 0, Selector: match anything, Action: lookup routing
+table \verb|local| (ID 255).
+The \verb|local| table is a special routing table containing
+high priority control routes for local and broadcast addresses.
+
+Rule 0 is special. It cannot be deleted or overridden.
+
+
+\item Priority: 32766, Selector: match anything, Action: lookup routing
+table \verb|main| (ID 254).
+The \verb|main| table is the normal routing table containing all non-policy
+routes. This rule may be deleted and/or overridden with other
+ones by the administrator.
+
+\item Priority: 32767, Selector: match anything, Action: lookup routing
+table \verb|default| (ID 253).
+The \verb|default| table is empty. It is reserved for some
+post-processing if no previous default rules selected the packet.
+This rule may also be deleted.
+
+\end{enumerate}
+
+Do not confuse routing tables with rules: rules point to routing tables,
+several rules may refer to one routing table and some routing tables
+may have no rules pointing to them. If the administrator deletes all the rules
+referring to a table, the table is not used, but it still exists
+and will disappear only after all the routes contained in it are deleted.
+
+
+\paragraph{Rule attributes:} Each RPDB entry has additional
+attributes. F.e.\ each rule has a pointer to some routing
+table. NAT and masquerading rules have an attribute to select new IP
+address to translate/masquerade. Besides that, rules have some
+optional attributes, which routes have, namely \verb|realms|.
+These values do not override those contained in the routing tables. They
+are only used if the route did not select any attributes.
+
+
+\paragraph{Rule types:} The RPDB may contain rules of the following
+types:
+\begin{itemize}
+\item \verb|unicast| --- the rule prescribes to return the route found
+in the routing table referenced by the rule.
+\item \verb|blackhole| --- the rule prescribes to silently drop the packet.
+\item \verb|unreachable| --- the rule prescribes to generate a ``Network
+is unreachable'' error.
+\item \verb|prohibit| --- the rule prescribes to generate
+``Communication is administratively prohibited'' error.
+\item \verb|nat| --- the rule prescribes to translate the source address
+of the IP packet into some other value. More about NAT is
+in Appendix~\ref{ROUTE-NAT}, p.\pageref{ROUTE-NAT}.
+\end{itemize}
+
+
+\paragraph{Commands:} \verb|add|, \verb|delete| and \verb|show|
+(or \verb|list|).
+
+\subsection{{\tt ip rule add} --- insert a new rule\\
+	{\tt ip rule delete} --- delete a rule}
+\label{IP-RULE-ADD}
+
+\paragraph{Abbreviations:} \verb|add|, \verb|a|; \verb|delete|, \verb|del|,
+	\verb|d|.
+
+\paragraph{Arguments:}
+
+\begin{itemize}
+\item \verb|type TYPE| (default)
+
+--- the type of this rule. The list of valid types was given in the previous
+subsection.
+
+\item \verb|from PREFIX|
+
+--- select the source prefix to match.
+
+\item \verb|to PREFIX|
+
+--- select the destination prefix to match.
+
+\item \verb|iif NAME|
+
+--- select the incoming device to match. If the interface is loopback,
+the rule only matches packets originating from this host. This means that you
+may create separate routing tables for forwarded and local packets and,
+hence, completely segregate them.
+
+\item \verb|tos TOS| or \verb|dsfield TOS|
+
+--- select the TOS value to match.
+
+\item \verb|fwmark MARK|
+
+--- select the \verb|fwmark| value to match.
+
+\item \verb|priority PREFERENCE|
+
+--- the priority of this rule. Each rule should have an explicitly
+set {\em unique\/} priority value.
+\begin{NB}
+  Really, for historical reasons \verb|ip rule add| does not require a
+  priority value and allows them to be non-unique.
+  If the user does not supplied a priority, it is selected by the kernel.
+  If the user creates a rule with a priority value that
+  already exists, the kernel does not reject the request. It adds
+  the new rule before all old rules of the same priority.
+
+  It is mistake in design, no more. And it will be fixed one day,
+  so do not rely on this feature. Use explicit priorities.
+\end{NB}
+
+
+\item \verb|table TABLEID|
+
+--- the routing table identifier to lookup if the rule selector matches.
+
+\item \verb|realms FROM/TO|
+
+--- Realms to select if the rule matched and the routing table lookup
+succeeded. Realm \verb|TO| is only used if the route did not select
+any realm.
+
+\item \verb|nat ADDRESS|
+
+--- The base of the IP address block to translate (for source addresses).
+The \verb|ADDRESS| may be either the start of the block of NAT addresses
+(selected by NAT routes) or in linux-2.2 a local host address (or even zero).
+In the last case the router does not translate the packets,
+but masquerades them to this address; this feature disappered in 2.4.
+More about NAT is in Appendix~\ref{ROUTE-NAT},
+p.\pageref{ROUTE-NAT}.
+
+\end{itemize}
+
+\paragraph{Warning:} Changes to the RPDB made with these commands
+do not become active immediately. It is assumed that after
+a script finishes a batch of updates, it flushes the routing cache
+with \verb|ip route flush cache|.
+
+\paragraph{Examples:}
+\begin{itemize}
+\item Route packets with source addresses from 192.203.80/24
+according to routing table \verb|inr.ruhep|:
+\begin{verbatim}
+ip ru add from 192.203.80.0/24 table inr.ruhep prio 220
+\end{verbatim}
+
+\item Translate packet source address 193.233.7.83 into 192.203.80.144
+and route it according to table \#1 (actually, it is \verb|inr.ruhep|):
+\begin{verbatim}
+ip ru add from 193.233.7.83 nat 192.203.80.144 table 1 prio 320
+\end{verbatim}
+
+\item Delete the unused default rule:
+\begin{verbatim}
+ip ru del prio 32767
+\end{verbatim}
+
+\end{itemize}
+
+
+
+\subsection{{\tt ip rule show} --- list rules}
+\label{IP-RULE-SHOW}
+
+\paragraph{Abbreviations:} \verb|show|, \verb|list|, \verb|sh|, \verb|ls|, \verb|l|.
+
+
+\paragraph{Arguments:} Good news, this is one command that has no arguments.
+
+\paragraph{Output format:}
+
+\begin{verbatim}
+kuznet@amber:~ $ ip ru ls
+0:	from all lookup local 
+200:	from 192.203.80.0/24 to 193.233.7.0/24 lookup main
+210:	from 192.203.80.0/24 to 192.203.80.0/24 lookup main
+220:	from 192.203.80.0/24 lookup inr.ruhep realms inr.ruhep/radio-msu
+300:	from 193.233.7.83 to 193.233.7.0/24 lookup main
+310:	from 193.233.7.83 to 192.203.80.0/24 lookup main
+320:	from 193.233.7.83 lookup inr.ruhep map-to 192.203.80.144
+32766:	from all lookup main 
+kuznet@amber:~ $
+\end{verbatim}
+
+In the first column is the rule priority value followed
+by a colon. Then the selectors follow. Each key is prefixed
+with the same keyword that was used to create the rule.
+
+The keyword \verb|lookup| is followed by a routing table identifier,
+as it is recorded in the file \verb|/etc/iproute2/rt_tables|.
+
+If the rule does NAT (f.e.\ rule \#320), it is shown by the keyword
+\verb|map-to| followed by the start of the block of addresses to map.
+
+The sense of this example is pretty simple. The prefixes
+192.203.80.0/24 and 193.233.7.0/24 form the internal network, but
+they are routed differently when the packets leave it.
+Besides that, the host 193.233.7.83 is translated into
+another prefix to look like 192.203.80.144 when talking
+to the outer world.
+
+\subsection{{\tt ip rule save} -- save rules tables}
+\label{IP-RULE-SAVE}
+
+\paragraph{Description:} this command saves the contents of the rules
+tables or the rule(s) selected by some criteria to standard output.
+
+\paragraph{Arguments:} \verb|ip rule save| has the same arguments as
+\verb|ip rule show|.
+
+\paragraph{Example:} This saves all the rules to the {\tt saved\_rules}
+file:
+\begin{verbatim}
+dan@caffeine:~ # ip rule save > saved_rules
+\end{verbatim}
+
+\paragraph{Output format:} The format of the data stream provided by
+\verb|ip rule save| is that of \verb|rtnetlink|.  See
+\verb|rtnetlink(7)| for more information.
+
+\subsection{{\tt ip rule restore} -- restore rules tables}
+\label{IP-RULE-RESTORE}
+
+\paragraph{Description:} this command restores the contents of the rules
+tables according to a data stream as provided by \verb|ip rule save| via
+standard input.  Note that any rules already in the table are left unchanged,
+and duplicates are not ignored.
+
+\paragraph{Arguments:} This command takes no arguments.
+
+\paragraph{Example:} This restores all rules that were saved to the
+{\tt saved\_rules} file:
+
+\begin{verbatim}
+dan@caffeine:~ # ip rule restore < saved_rules
+\end{verbatim}
+
+
+
+\section{{\tt ip maddress} --- multicast addresses management}
+\label{IP-MADDR}
+
+\paragraph{Object:} \verb|maddress| objects are multicast addresses.
+
+\paragraph{Commands:} \verb|add|, \verb|delete|, \verb|show| (or \verb|list|).
+
+\subsection{{\tt ip maddress show} --- list multicast addresses}
+
+\paragraph{Abbreviations:} \verb|show|, \verb|list|, \verb|sh|, \verb|ls|, \verb|l|.
+
+\paragraph{Arguments:}
+
+\begin{itemize}
+
+\item \verb|dev NAME| (default)
+
+--- the device name.
+
+\end{itemize}
+
+\paragraph{Output format:}
+
+\begin{verbatim}
+kuznet@alisa:~ $ ip maddr ls dummy
+2:  dummy
+    link  33:33:00:00:00:01
+    link  01:00:5e:00:00:01
+    inet  224.0.0.1 users 2
+    inet6 ff02::1
+kuznet@alisa:~ $ 
+\end{verbatim}
+
+The first line of the output shows the interface index and its name.
+Then the multicast address list follows. Each line starts with the
+protocol identifier. The word \verb|link| denotes a link layer
+multicast addresses.
+
+If a multicast address has more than one user, the number
+of users is shown after the \verb|users| keyword.
+
+One additional feature not present in the example above
+is the \verb|static| flag, which indicates that the address was joined
+with \verb|ip maddr add|. See the following subsection.
+
+
+
+\subsection{{\tt ip maddress add} --- add a multicast address\\
+	    {\tt ip maddress delete} --- delete a multicast address}
+
+\paragraph{Abbreviations:} \verb|add|, \verb|a|; \verb|delete|, \verb|del|, \verb|d|.
+
+\paragraph{Description:} these commands attach/detach
+a static link layer multicast address to listen on the interface.
+Note that it is impossible to join protocol multicast groups
+statically. This command only manages link layer addresses.
+
+
+\paragraph{Arguments:}
+
+\begin{itemize}
+\item \verb|address LLADDRESS| (default)
+
+--- the link layer multicast address.
+
+\item \verb|dev NAME|
+
+--- the device to join/leave this multicast address.
+
+\end{itemize}
+
+
+\paragraph{Example:} Let us continue with the example from the previous subsection.
+
+\begin{verbatim}
+netadm@alisa:~ # ip maddr add 33:33:00:00:00:01 dev dummy
+netadm@alisa:~ # ip -0 maddr ls dummy
+2:  dummy
+    link  33:33:00:00:00:01 users 2 static
+    link  01:00:5e:00:00:01
+netadm@alisa:~ # ip maddr del 33:33:00:00:00:01 dev dummy
+\end{verbatim}
+
+\begin{NB}
+ Neither \verb|ip| nor the kernel check for multicast address validity.
+ Particularly, this means that you can try to load a unicast address
+ instead of a multicast address. Most drivers will ignore such addresses,
+ but several (f.e.\ Tulip) will intern it to their on-board filter.
+ The effects may be strange. Namely, the addresses become additional
+ local link addresses and, if you loaded the address of another host
+ to the router, wait for duplicated packets on the wire.
+ It is not a bug, but rather a hole in the API and intra-kernel interfaces.
+ This feature is really more useful for traffic monitoring, but using it
+ with Linux-2.2 you {\em have to\/} be sure that the host is not
+ a router and, especially, that it is not a transparent proxy or masquerading
+ agent.
+\end{NB}
+
+
+
+\section{{\tt ip mroute} --- multicast routing cache management}
+\label{IP-MROUTE}
+
+\paragraph{Abbreviations:} \verb|mroute|, \verb|mr|.
+
+\paragraph{Object:} \verb|mroute| objects are multicast routing cache
+entries created by a user level mrouting daemon
+(f.e.\ \verb|pimd| or \verb|mrouted|).
+
+Due to the limitations of the current interface to the multicast routing
+engine, it is impossible to change \verb|mroute| objects administratively,
+so we may only display them. This limitation will be removed
+in the future.
+
+\paragraph{Commands:} \verb|show| (or \verb|list|).
+
+
+\subsection{{\tt ip mroute show} --- list mroute cache entries}
+
+\paragraph{Abbreviations:} \verb|show|, \verb|list|, \verb|sh|, \verb|ls|, \verb|l|.
+
+\paragraph{Arguments:}
+
+\begin{itemize}
+\item \verb|to PREFIX| (default)
+
+--- the prefix selecting the destination multicast addresses to list.
+
+
+\item \verb|iif NAME|
+
+--- the interface on which multicast packets are received.
+
+
+\item \verb|from PREFIX|
+
+--- the prefix selecting the IP source addresses of the multicast route.
+
+
+\end{itemize}
+
+\paragraph{Output format:}
+
+\begin{verbatim}
+kuznet@amber:~ $ ip mroute ls
+(193.232.127.6, 224.0.1.39)      Iif: unresolved 
+(193.232.244.34, 224.0.1.40)     Iif: unresolved 
+(193.233.7.65, 224.66.66.66)     Iif: eth0       Oifs: pimreg 
+kuznet@amber:~ $ 
+\end{verbatim}
+
+Each line shows one (S,G) entry in the multicast routing cache,
+where S is the source address and G is the multicast group. \verb|Iif| is
+the interface on which multicast packets are expected to arrive.
+If the word \verb|unresolved| is there instead of the interface name,
+it means that the routing daemon still hasn't resolved this entry.
+The keyword \verb|oifs| is followed by a list of output interfaces, separated
+by spaces. If a multicast routing entry is created with non-trivial
+TTL scope, administrative distances are appended to the device names
+in the \verb|oifs| list.
+
+\paragraph{Statistics:} The \verb|-statistics| option also prints the
+number of packets and bytes forwarded along this route and
+the number of packets that arrived on the wrong interface, if this number is not zero.
+
+\begin{verbatim}
+kuznet@amber:~ $ ip -s mr ls 224.66/16
+(193.233.7.65, 224.66.66.66)     Iif: eth0       Oifs: pimreg 
+  9383 packets, 300256 bytes
+kuznet@amber:~ $
+\end{verbatim}
+
+
+\section{{\tt ip tunnel} --- tunnel configuration}
+\label{IP-TUNNEL}
+
+\paragraph{Abbreviations:} \verb|tunnel|, \verb|tunl|.
+
+\paragraph{Object:} \verb|tunnel| objects are tunnels, encapsulating
+packets in IPv4 packets and then sending them over the IP infrastructure.
+
+\paragraph{Commands:} \verb|add|, \verb|delete|, \verb|change|, \verb|show|
+(or \verb|list|).
+
+\paragraph{See also:} A more informal discussion of tunneling
+over IP and the \verb|ip tunnel| command can be found in~\cite{IP-TUNNELS}.
+
+\subsection{{\tt ip tunnel add} --- add a new tunnel\\
+	{\tt ip tunnel change} --- change an existing tunnel\\
+	{\tt ip tunnel delete} --- destroy a tunnel}
+
+\paragraph{Abbreviations:} \verb|add|, \verb|a|; \verb|change|, \verb|chg|;
+\verb|delete|, \verb|del|, \verb|d|.
+
+
+\paragraph{Arguments:}
+
+\begin{itemize}
+
+\item \verb|name NAME| (default)
+
+--- select the tunnel device name.
+
+\item \verb|mode MODE|
+
+--- set the tunnel mode. Three modes are currently available:
+	\verb|ipip|, \verb|sit| and \verb|gre|.
+
+\item \verb|remote ADDRESS|
+
+--- set the remote endpoint of the tunnel.
+
+\item \verb|local ADDRESS|
+
+--- set the fixed local address for tunneled packets.
+It must be an address on another interface of this host.
+
+\item \verb|ttl N|
+
+--- set a fixed TTL \verb|N| on tunneled packets.
+	\verb|N| is a number in the range 1--255. 0 is a special value
+	meaning that packets inherit the TTL value. 
+		The default value is: \verb|inherit|.
+
+\item \verb|tos T| or \verb|dsfield T|
+
+--- set a fixed TOS \verb|T| on tunneled packets.
+		The default value is: \verb|inherit|.
+
+
+
+\item \verb|dev NAME| 
+
+--- bind the tunnel to the device \verb|NAME| so that
+	tunneled packets will only be routed via this device and will
+	not be able to escape to another device when the route to endpoint changes.
+
+\item \verb|nopmtudisc|
+
+--- disable Path MTU Discovery on this tunnel.
+	It is enabled by default. Note that a fixed ttl is incompatible
+	with this option: tunnelling with a fixed ttl always makes pmtu discovery.
+
+\item \verb|key K|, \verb|ikey K|, \verb|okey K|
+
+--- (only GRE tunnels) use keyed GRE with key \verb|K|. \verb|K| is
+	either a number or an IP address-like dotted quad.
+   The \verb|key| parameter sets the key to use in both directions.
+   The \verb|ikey| and \verb|okey| parameters set different keys for input and output.
+   
+
+\item \verb|csum|, \verb|icsum|, \verb|ocsum|
+
+--- (only GRE tunnels) generate/require checksums for tunneled packets.
+   The \verb|ocsum| flag calculates checksums for outgoing packets.
+   The \verb|icsum| flag requires that all input packets have the correct
+   checksum. The \verb|csum| flag is equivalent to the combination
+  ``\verb|icsum| \verb|ocsum|''.
+
+\item \verb|seq|, \verb|iseq|, \verb|oseq|
+
+--- (only GRE tunnels) serialize packets.
+   The \verb|oseq| flag enables sequencing of outgoing packets.
+   The \verb|iseq| flag requires that all input packets are serialized.
+   The \verb|seq| flag is equivalent to the combination ``\verb|iseq| \verb|oseq|''.
+
+\begin{NB}
+ I think this option does not
+	work. At least, I did not test it, did not debug it and
+	do not even understand how it is supposed to work or for what
+	purpose Cisco planned to use it. Do not use it.
+\end{NB}
+
+
+\end{itemize}
+
+\paragraph{Example:} Create a pointopoint IPv6 tunnel with maximal TTL of 32.
+\begin{verbatim}
+netadm@amber:~ # ip tunl add Cisco mode sit remote 192.31.7.104 \
+    local 192.203.80.142 ttl 32 
+\end{verbatim}
+
+\subsection{{\tt ip tunnel show} --- list tunnels}
+
+\paragraph{Abbreviations:} \verb|show|, \verb|list|, \verb|sh|, \verb|ls|, \verb|l|.
+
+
+\paragraph{Arguments:} None.
+
+\paragraph{Output format:}
+\begin{verbatim}
+kuznet@amber:~ $ ip tunl ls Cisco
+Cisco: ipv6/ip  remote 192.31.7.104  local 192.203.80.142  ttl 32 
+kuznet@amber:~ $ 
+\end{verbatim}
+The line starts with the tunnel device name followed by a colon.
+Then the tunnel mode follows. The parameters of the tunnel are listed
+with the same keywords that were used when creating the tunnel.
+
+\paragraph{Statistics:}
+
+\begin{verbatim}
+kuznet@amber:~ $ ip -s tunl ls Cisco
+Cisco: ipv6/ip  remote 192.31.7.104  local 192.203.80.142  ttl 32 
+RX: Packets    Bytes        Errors CsumErrs OutOfSeq Mcasts
+    12566      1707516      0      0        0        0       
+TX: Packets    Bytes        Errors DeadLoop NoRoute  NoBufs
+    13445      1879677      0      0        0        0     
+kuznet@amber:~ $ 
+\end{verbatim}
+Essentially, these numbers are the same as the numbers
+printed with {\tt ip -s link show}
+(sec.\ref{IP-LINK-SHOW}, p.\pageref{IP-LINK-SHOW}) but the tags are different
+to reflect that they are tunnel specific.
+\begin{itemize}
+\item \verb|CsumErrs| --- the total number of packets dropped
+because of checksum failures for a GRE tunnel with checksumming enabled.
+\item \verb|OutOfSeq| --- the total number of packets dropped
+because they arrived out of sequence for a GRE tunnel with
+serialization enabled.
+\item \verb|Mcasts| --- the total number of multicast packets
+received on a broadcast GRE tunnel.
+\item \verb|DeadLoop| --- the total number of packets which were not
+transmitted because the tunnel is looped back to itself.
+\item \verb|NoRoute| --- the total number of packets which were not
+transmitted because there is no IP route to the remote endpoint.
+\item \verb|NoBufs| --- the total number of packets which were not
+transmitted because the kernel failed to allocate a buffer.
+\end{itemize}
+
+
+\section{{\tt ip monitor} and {\tt rtmon} --- state monitoring}
+\label{IP-MONITOR}
+
+The \verb|ip| utility can monitor the state of devices, addresses
+and routes continuously. This option has a slightly different format.
+Namely,
+the \verb|monitor| command is the first in the command line and then
+the object list follows:
+\begin{verbatim}
+  ip monitor [ file FILE ] [ all | OBJECT-LIST ] [ label ]
+\end{verbatim}
+\verb|OBJECT-LIST| is the list of object types that we want to
+monitor.  It may contain \verb|link|, \verb|address| and \verb|route|.
+Specifying \verb|label| indicates that output lines should be labelled
+with the type of object being printed --- this happens by default if
+\verb|all| is specified.  If no \verb|file| argument is given,
+\verb|ip| opens RTNETLINK, listens on it and dumps state changes in
+the format described in previous sections.
+
+If a file name is given, it does not listen on RTNETLINK,
+but opens the file containing RTNETLINK messages saved in binary format
+and dumps them. Such a history file can be generated with the
+\verb|rtmon| utility. This utility has a command line syntax similar to
+\verb|ip monitor|.
+Ideally, \verb|rtmon| should be started before
+the first network configuration command is issued. F.e.\ if
+you insert:
+\begin{verbatim}
+  rtmon file /var/log/rtmon.log
+\end{verbatim}
+in a startup script, you will be able to view the full history
+later.
+
+Certainly, it is possible to start \verb|rtmon| at any time.
+It prepends the history with the state snapshot dumped at the moment
+of starting.
+
+
+\section{Route realms and policy propagation, {\tt rtacct}}
+\label{RT-REALMS}
+
+On routers using OSPF ASE or, especially, the BGP protocol, routing
+tables may be huge. If we want to classify or to account for the packets
+per route, we will have to keep lots of information. Even worse, if we
+want to distinguish the packets not only by their destination, but
+also by their source, the task gets quadratic complexity and its solution
+is physically impossible.
+
+One approach to propagating the policy from routing protocols
+to the forwarding engine has been proposed in~\cite{IOS-BGP-PP}.
+Essentially, Cisco Policy Propagation via BGP is based on the fact
+that dedicated routers all have the RIB (Routing Information Base)
+close to the forwarding engine, so policy routing rules can
+check all the route attributes, including ASPATH information
+and community strings.
+
+The Linux architecture, splitting the RIB (maintained by a user level
+daemon) and the kernel based FIB (Forwarding Information Base),
+does not allow such a simple approach.
+
+It is to our fortune because there is another solution
+which allows even more flexible policy and richer semantics.
+
+Namely, routes can be clustered together in user space, based on their
+attributes.  F.e.\ a BGP router knows route ASPATH, its community;
+an OSPF router knows the route tag or its area. The administrator, when adding
+routes manually, also knows their nature. Providing that the number of such
+aggregates (we call them {\em realms\/}) is low, the task of full
+classification both by source and destination becomes quite manageable.
+
+So each route may be assigned to a realm. It is assumed that
+this identification is made by a routing daemon, but static routes
+can also be handled manually with \verb|ip route| (see sec.\ref{IP-ROUTE},
+p.\pageref{IP-ROUTE}).
+\begin{NB}
+  There is a patch to \verb|gated|, allowing classification of routes
+  to realms with all the set of policy rules implemented in \verb|gated|:
+  by prefix, by ASPATH, by origin, by tag etc.
+\end{NB}
+
+To facilitate the construction (f.e.\ in case the routing
+daemon is not aware of realms), missing realms may be completed
+with routing policy rules, see sec.~\ref{IP-RULE}, p.\pageref{IP-RULE}.
+
+For each packet the kernel calculates a tuple of realms: source realm
+and destination realm, using the following algorithm:
+
+\begin{enumerate}
+\item If the route has a realm, the destination realm of the packet is set to it.
+\item If the rule has a source realm, the source realm of the packet is set to it.
+If the destination realm was not inherited from the route and the rule has a destination realm,
+it is also set.
+\item If at least one of the realms is still unknown, the kernel finds
+the reversed route to the source of the packet.
+\item If the source realm is still unknown, get it from the reversed route.
+\item If one of the realms is still unknown, swap the realms of reversed
+routes and apply step 2 again.
+\end{enumerate}
+
+After this procedure is completed we know what realm the packet
+arrived from and the realm where it is going to propagate to.
+If some of the realms are unknown, they are initialized to zero
+(or realm \verb|unknown|).
+
+The main application of realms is the TC \verb|route| classifier~\cite{TC-CREF},
+where they are used to help assign packets to traffic classes,
+to account, police and schedule them according to this
+classification.
+
+A much simpler but still very useful application is incoming packet
+accounting by realms. The kernel gathers a packet statistics summary
+which can be viewed with the \verb|rtacct| utility.
+\begin{verbatim}
+kuznet@amber:~ $ rtacct russia
+Realm      BytesTo    PktsTo     BytesFrom  PktsFrom   
+russia     20576778   169176     47080168   153805     
+kuznet@amber:~ $
+\end{verbatim}
+This shows that this router received 153805 packets from
+the realm \verb|russia| and forwarded 169176 packets to \verb|russia|.
+The realm \verb|russia| consists of routes with ASPATHs not leaving
+Russia.
+
+Note that locally originating packets are not accounted here,
+\verb|rtacct| shows incoming packets only. Using the \verb|route|
+classifier (see~\cite{TC-CREF}) you can get even more detailed
+accounting information about outgoing packets, optionally
+summarizing traffic not only by source or destination, but
+by any pair of source and destination realms.
+
+
+\begin{thebibliography}{99}
+\addcontentsline{toc}{section}{References}
+\bibitem{RFC-NDISC} T.~Narten, E.~Nordmark, W.~Simpson.
+``Neighbor Discovery for IP Version 6 (IPv6)'', RFC-2461.
+
+\bibitem{RFC-ADDRCONF} S.~Thomson, T.~Narten.
+``IPv6 Stateless Address Autoconfiguration'', RFC-2462.
+
+\bibitem{RFC1812} F.~Baker.
+``Requirements for IP Version 4 Routers'', RFC-1812.
+
+\bibitem{RFC1122} R.~T.~Braden.
+``Requirements for Internet hosts --- communication layers'', RFC-1122.
+
+\bibitem{IOS} ``Cisco IOS Release 12.0 Network Protocols
+Command Reference, Part 1'' and
+``Cisco IOS Release 12.0 Quality of Service Solutions
+Configuration Guide: Configuring Policy-Based Routing'',\\
+http://www.cisco.com/univercd/cc/td/doc/product/software/ios120.
+
+\bibitem{IP-TUNNELS} A.~N.~Kuznetsov.
+``Tunnels over IP in Linux-2.2'', \\
+In: {\tt ftp://ftp.inr.ac.ru/ip-routing/iproute2-current.tar.gz}.
+
+\bibitem{TC-CREF} A.~N.~Kuznetsov. ``TC Command Reference'',\\
+In: {\tt ftp://ftp.inr.ac.ru/ip-routing/iproute2-current.tar.gz}.
+
+\bibitem{IOS-BGP-PP} ``Cisco IOS Release 12.0 Quality of Service Solutions
+Configuration Guide: Configuring QoS Policy Propagation via
+Border Gateway Protocol'',\\
+http://www.cisco.com/univercd/cc/td/doc/product/software/ios120.
+
+\bibitem{RFC-DHCP} R.~Droms.
+``Dynamic Host Configuration Protocol.'', RFC-2131
+
+\bibitem{RFC2414}  M.~Allman, S.~Floyd, C.~Partridge.
+``Increasing TCP's Initial Window'', RFC-2414.
+
+\end{thebibliography}
+
+
+
+
+\appendix
+\addcontentsline{toc}{section}{Appendix}
+
+\section{Source address selection}
+\label{ADDR-SEL}
+
+When a host creates an IP packet, it must select some source
+address. Correct source address selection is a critical procedure,
+because it gives the receiver the information needed to deliver a
+reply. If the source is selected incorrectly, in the best case,
+the backward path may appear different to the forward one which
+is harmful for performance. In the worst case, when the addresses
+are administratively scoped, the reply may be lost entirely.
+
+Linux-2.2 selects source addresses using the following algorithm:
+
+\begin{itemize}
+\item
+The application may select a source address explicitly with \verb|bind(2)|
+syscall or supplying it to \verb|sendmsg(2)| via the ancillary data object
+\verb|IP_PKTINFO|. In this case the kernel only checks the validity
+of the address and never tries to ``improve'' an incorrect user choice,
+generating an error instead.
+\begin{NB}
+ Never say ``Never''. The sysctl option \verb|ip_dynaddr| breaks
+ this axiom. It has been made deliberately with the purpose
+ of automatically reselecting the address on hosts with dynamic dial-out interfaces.
+ However, this hack {\em must not\/} be used on multihomed hosts
+ and especially on routers: it would break them.
+\end{NB}
+
+
+\item Otherwise, IP routing tables can contain an explicit source
+address hint for this destination. The hint is set with the \verb|src| parameter
+to the \verb|ip route| command, sec.\ref{IP-ROUTE}, p.\pageref{IP-ROUTE}.
+
+
+\item Otherwise, the kernel searches through the list of addresses
+attached to the interface through which the packets will be routed.
+The search strategies are different for IP and IPv6. Namely:
+
+\begin{itemize}
+\item IPv6 searches for the first valid, not deprecated address
+with the same scope as the destination.
+
+\item IP searches for the first valid address with a scope wider
+than the scope of the destination but it prefers addresses
+which fall to the same subnet as the nexthop of the route
+to the destination. Unlike IPv6, the scopes of IPv4 destinations
+are not encoded in their addresses but are supplied
+in routing tables instead (the \verb|scope| parameter to the \verb|ip route| command,
+sec.\ref{IP-ROUTE}, p.\pageref{IP-ROUTE}).
+
+\end{itemize}
+
+
+\item Otherwise, if the scope of the destination is \verb|link| or \verb|host|,
+the algorithm fails and returns a zero source address.
+
+\item Otherwise, all interfaces are scanned to search for an address
+with an appropriate scope. The loopback device \verb|lo| is always the first
+in the search list, so that if an address with global scope (not 127.0.0.1!)
+is configured on loopback, it is always preferred.
+
+\end{itemize}
+
+
+\section{Proxy ARP/NDISC}
+\label{PROXY-NEIGH}
+
+Routers may answer ARP/NDISC solicitations on behalf of other hosts.
+In Linux-2.2 proxy ARP on an interface may be enabled
+by setting the kernel \verb|sysctl| variable 
+\verb|/proc/sys/net/ipv4/conf/<dev>/proxy_arp| to 1. After this, the router
+starts to answer ARP requests on the interface \verb|<dev>|, provided
+the route to the requested destination does {\em not\/} go back via the same
+device.
+
+The variable \verb|/proc/sys/net/ipv4/conf/all/proxy_arp| enables proxy
+ARP on all the IP devices.
+
+However, this approach fails in the case of IPv6 because the router
+must join the solicited node multicast address to listen for the corresponding
+NDISC queries. It means that proxy NDISC is possible only on a per destination
+basis.
+
+Logically, proxy ARP/NDISC is not a kernel task. It can easily be implemented
+in user space. However, similar functionality was present in BSD kernels
+and in Linux-2.0, so we have to preserve it at least to the extent that
+is standardized in BSD.
+\begin{NB}
+  Linux-2.0 ARP had a feature called {\em subnet\/} proxy ARP.
+  It is replaced with the sysctl flag in Linux-2.2.
+\end{NB}
+
+
+The \verb|ip| utility provides a way to manage proxy ARP/NDISC
+with the \verb|ip neigh| command, namely:
+\begin{verbatim}
+  ip neigh add proxy ADDRESS [ dev NAME ]
+\end{verbatim}
+adds a new proxy ARP/NDISC record and
+\begin{verbatim}
+  ip neigh del proxy ADDRESS [ dev NAME ]
+\end{verbatim}
+deletes it.
+
+If the name of the device is not given, the router will answer solicitations
+for address \verb|ADDRESS| on all devices, otherwise it will only serve
+the device \verb|NAME|. Even if the proxy entry is created with
+\verb|ip neigh|, the router {\em will not\/} answer a query if the route
+to the destination goes back via the interface from which the solicitation
+was received.
+
+It is important to emphasize that proxy entries have {\em no\/}
+parameters other than these (IP/IPv6 address and optional device).
+Particularly, the entry does not store any link layer address.
+It always advertises the station address of the interface
+on which it sends advertisements (i.e. it's own station address).
+
+\section{Route NAT status}
+\label{ROUTE-NAT}
+
+NAT (or ``Network Address Translation'') remaps some parts
+of the IP address space into other ones. Linux-2.2 route NAT is supposed
+to be used to facilitate policy routing by rewriting addresses
+to other routing domains or to help while renumbering sites
+to another prefix.
+
+\paragraph{What it is not:}
+It is necessary to emphasize that {\em it is not supposed\/}
+to be used to compress address space or to split load.
+This is not missing functionality but a design principle.
+Route NAT is {\em stateless\/}. It does not hold any state
+about translated sessions. This means that it handles any number
+of sessions flawlessly. But it also means that it is {\em static\/}.
+It cannot detect the moment when the last TCP client stops
+using an address. For the same reason, it will not help to split
+load between several servers.
+\begin{NB}
+It is a pretty commonly held belief that it is useful to split load between
+several servers with NAT. This is a mistake. All you get from this
+is the requirement that the router keep the state of all the TCP connections
+going via it. Well, if the router is so powerful, run apache on it. 8)
+\end{NB}
+
+The second feature: it does not touch packet payload,
+does not try to ``improve'' broken protocols by looking
+through its data and mangling it. It mangles IP addresses,
+only IP addresses and nothing but IP addresses.
+This also, is not missing any functionality.
+
+To resume: if you need to compress address space or keep
+active FTP clients happy, your choice is not route NAT but masquerading,
+port forwarding, NAPT etc. 
+\begin{NB}
+By the way, you may also want to look at
+http://www.suse.com/\~mha/HyperNews/get/linux-ip-nat.html
+\end{NB}
+
+
+\paragraph{How it works.}
+Some part of the address space is reserved for dummy addresses
+which will look for all the world like some host addresses
+inside your network. No other hosts may use these addresses,
+however other routers may also be configured to translate them.
+\begin{NB}
+A great advantage of route NAT is that it may be used not
+only in stub networks but in environments with arbitrarily complicated
+structure. It does not firewall, it {\em forwards.}
+\end{NB}
+These addresses are selected by the \verb|ip route| command
+(sec.\ref{IP-ROUTE-ADD}, p.\pageref{IP-ROUTE-ADD}). F.e.\
+\begin{verbatim}
+  ip route add nat 192.203.80.144 via 193.233.7.83
+\end{verbatim}
+states that the single address 192.203.80.144 is a dummy NAT address.
+For all the world it looks like a host address inside our network.
+For neighbouring hosts and routers it looks like the local address
+of the translating router. The router answers ARP for it, advertises
+this address as routed via it, {\em et al\/}. When the router
+receives a packet destined for 192.203.80.144, it replaces 
+this address with 193.233.7.83 which is the address of some real
+host and forwards the packet. If you need to remap
+blocks of addresses, you may use a command like:
+\begin{verbatim}
+  ip route add nat 192.203.80.192/26 via 193.233.7.64
+\end{verbatim}
+This command will map a block of 63 addresses 192.203.80.192-255 to
+193.233.7.64-127.
+
+When an internal host (193.233.7.83 in the example above)
+sends something to the outer world and these packets are forwarded
+by our router, it should translate the source address 193.233.7.83
+into 192.203.80.144. This task is solved by setting a special
+policy rule (sec.\ref{IP-RULE-ADD}, p.\pageref{IP-RULE-ADD}):
+\begin{verbatim}
+  ip rule add prio 320 from 193.233.7.83 nat 192.203.80.144
+\end{verbatim}
+This rule says that the source address 193.233.7.83
+should be translated into 192.203.80.144 before forwarding.
+It is important that the address after the \verb|nat| keyword
+is some NAT address, declared by {\tt ip route add nat}.
+If it is just a random address the router will not map to it.
+\begin{NB}
+The exception is when the address is a local address of this
+router (or 0.0.0.0) and masquerading is configured in the linux-2.2
+kernel. In this case the router will masquerade the packets as this address.
+If 0.0.0.0 is selected, the result is equivalent to one
+obtained with firewalling rules. Otherwise, you have the way
+to order Linux to masquerade to this fixed address.
+NAT mechanism used in linux-2.4 is more flexible than
+masquerading, so that this feature has lost meaning and disabled.
+\end{NB}
+
+If the network has non-trivial internal structure, it is
+useful and even necessary to add rules disabling translation
+when a packet does not leave this network. Let us return to the
+example from sec.\ref{IP-RULE-SHOW} (p.\pageref{IP-RULE-SHOW}).
+\begin{verbatim}
+300:	from 193.233.7.83 to 193.233.7.0/24 lookup main
+310:	from 193.233.7.83 to 192.203.80.0/24 lookup main
+320:	from 193.233.7.83 lookup inr.ruhep map-to 192.203.80.144
+\end{verbatim}
+This block of rules causes normal forwarding when
+packets from 193.233.7.83 do not leave networks 193.233.7/24
+and 192.203.80/24. Also, if the \verb|inr.ruhep| table does not
+contain a route to the destination (which means that the routing
+domain owning addresses from 192.203.80/24 is dead), no translation
+will occur. Otherwise, the packets are translated.
+
+\paragraph{How to only translate selected ports:}
+If you only want to translate selected ports (f.e.\ http)
+and leave the rest intact, you may use \verb|ipchains|
+to \verb|fwmark| a class of packets.
+Suppose you did and all the packets from 193.233.7.83
+destined for port 80 are marked with marker 0x1234 in input fwchain.
+In this case you may replace rule \#320 with:
+\begin{verbatim}
+320:	from 193.233.7.83 fwmark 1234 lookup main map-to 192.203.80.144
+\end{verbatim}
+and translation will only be enabled for outgoing http requests.
+
+\section{Example: minimal host setup}
+\label{EXAMPLE-SETUP}
+
+The following script gives an example of a fault safe
+setup of IP (and IPv6, if it is compiled into the kernel)
+in the common case of a node attached to a single broadcast
+network. A more advanced script, which may be used both on multihomed
+hosts and on routers, is described in the following
+section.
+
+The utilities used in the script may be found in the
+directory ftp://ftp.inr.ac.ru/ip-routing/:
+\begin{enumerate}
+\item \verb|ip| --- package \verb|iproute2|.
+\item \verb|arping| --- package \verb|iputils|.
+\item \verb|rdisc| --- package \verb|iputils|.
+\end{enumerate}
+\begin{NB}
+It also refers to a DHCP client, \verb|dhcpcd|. I should refrain from
+recommending a good DHCP client to use. All that I can
+say is that ISC \verb|dhcp-2.0b1pl6| patched with the patch that
+can be found in the \verb|dhcp.bootp.rarp| subdirectory of
+the same ftp site {\em does\/} work,
+at least on Ethernet and Token Ring.
+\end{NB}
+
+\begin{verbatim}
+#! /bin/bash
+\end{verbatim}
+\begin{flushleft}
+\# {\bf Usage: \verb|ifone ADDRESS[/PREFIX-LENGTH] [DEVICE]|}\\
+\# {\bf Parameters:}\\
+\# \$1 --- Static IP address, optionally followed by prefix length.\\
+\# \$2 --- Device name. If it is missing, \verb|eth0| is asssumed.\\
+\# F.e. \verb|ifone 193.233.7.90|
+\end{flushleft}
+\begin{verbatim}
+dev=$2
+: ${dev:=eth0}
+ipaddr=
+\end{verbatim}
+\# Parse IP address, splitting prefix length.
+\begin{verbatim}
+if [ "$1" != "" ]; then
+  ipaddr=${1%/*}
+  if [ "$1" != "$ipaddr" ]; then
+    pfxlen=${1#*/}
+  fi
+  : ${pfxlen:=24}
+fi
+pfx="${ipaddr}/${pfxlen}"
+\end{verbatim}
+
+\begin{flushleft}
+\# {\bf Step 0} --- enable loopback.\\
+\#\\
+\# This step is necessary on any networked box before attempt\\
+\# to configure any other device.\\
+\end{flushleft}
+\begin{verbatim}
+ip link set up dev lo
+ip addr add 127.0.0.1/8 dev lo brd + scope host
+\end{verbatim}
+\begin{flushleft}
+\# IPv6 autoconfigure themself on loopback.\\
+\#\\
+\# If user gave loopback as device, we add the address as alias and exit.
+\end{flushleft}
+\begin{verbatim}
+if [ "$dev" = "lo" ]; then
+  if [ "$ipaddr" != "" -a  "$ipaddr" != "127.0.0.1" ]; then
+    ip address add $ipaddr dev $dev
+    exit $?
+  fi
+  exit 0
+fi
+\end{verbatim}
+
+\noindent\# {\bf Step 1} --- enable device \verb|$dev|
+
+\begin{verbatim}
+if ! ip link set up dev $dev ; then
+  echo "Cannot enable interface $dev. Aborting." 1>&2
+  exit 1
+fi
+\end{verbatim}
+\begin{flushleft}
+\# The interface is \verb|UP|. IPv6 started stateless autoconfiguration itself,\\
+\# and its configuration finishes here. However,\\
+\# IP still needs some static preconfigured address.
+\end{flushleft}
+\begin{verbatim}
+if [ "$ipaddr" = "" ]; then
+  echo "No address for $dev is configured, trying DHCP..." 1>&2
+  dhcpcd
+  exit $?
+fi
+\end{verbatim}
+
+\begin{flushleft}
+\# {\bf Step 2} --- IP Duplicate Address Detection~\cite{RFC-DHCP}.\\
+\# Send two probes and wait for result for 3 seconds.\\
+\# If the interface opens slower f.e.\ due to long media detection,\\
+\# you want to increase the timeout.\\
+\end{flushleft}
+\begin{verbatim}
+if ! arping -q -c 2 -w 3 -D -I $dev $ipaddr ; then
+  echo "Address $ipaddr is busy, trying DHCP..." 1>&2
+  dhcpcd
+  exit $?
+fi
+\end{verbatim}
+\begin{flushleft}
+\# OK, the address is unique, we may add it on the interface.\\
+\#\\
+\# {\bf Step 3} --- Configure the address on the interface.
+\end{flushleft}
+
+\begin{verbatim}
+if ! ip address add $pfx brd + dev $dev; then
+  echo "Failed to add $pfx on $dev, trying DHCP..." 1>&2
+  dhcpcd
+  exit $?
+fi
+\end{verbatim}
+
+\noindent\# {\bf Step 4} --- Announce our presence on the link.
+\begin{verbatim}
+arping -A -c 1 -I $dev $ipaddr
+noarp=$?
+( sleep 2;
+  arping -U -c 1 -I $dev $ipaddr ) >& /dev/null </dev/null &
+\end{verbatim}
+
+\begin{flushleft}
+\# {\bf Step 5} (optional) --- Add some control routes.\\
+\#\\
+\# 1. Prohibit link local multicast addresses.\\
+\# 2. Prohibit link local (alias, limited) broadcast.\\
+\# 3. Add default multicast route.
+\end{flushleft}
+\begin{verbatim}
+ip route add unreachable 224.0.0.0/24 
+ip route add unreachable 255.255.255.255
+if [ `ip link ls $dev | grep -c MULTICAST` -ge 1 ]; then
+  ip route add 224.0.0.0/4 dev $dev scope global
+fi
+\end{verbatim}
+
+\begin{flushleft}
+\# {\bf Step 6} --- Add fallback default route with huge metric.\\
+\# If a proxy ARP server is present on the interface, we will be\\
+\# able to talk to all the Internet without further configuration.\\
+\# It is not so cheap though and we still hope that this route\\
+\# will be overridden by more correct one by rdisc.\\
+\# Do not make this step if the device is not ARPable,\\
+\# because dead nexthop detection does not work on them.
+\end{flushleft}
+\begin{verbatim}
+if [ "$noarp" = "0" ]; then
+  ip ro add default dev $dev metric 30000 scope global
+fi
+\end{verbatim}
+
+\begin{flushleft}
+\# {\bf Step 7} --- Restart router discovery and exit.
+\end{flushleft}
+\begin{verbatim}
+killall -HUP rdisc || rdisc -fs
+exit 0
+\end{verbatim}
+
+
+\section{Example: {\protect\tt ifcfg} --- interface address management}
+\label{EXAMPLE-IFCFG}
+
+This is a simplistic script replacing one option of \verb|ifconfig|,
+namely, IP address management. It not only adds
+addresses, but also carries out Duplicate Address Detection~\cite{RFC-DHCP},
+sends unsolicited ARP to update the caches of other hosts sharing
+the interface, adds some control routes and restarts Router Discovery
+when it is necessary.
+
+I strongly recommend using it {\em instead\/} of \verb|ifconfig| both
+on hosts and on routers.
+
+\begin{verbatim}
+#! /bin/bash
+\end{verbatim}
+\begin{flushleft}
+\# {\bf Usage: \verb?ifcfg DEVICE[:ALIAS] [add|del] ADDRESS[/LENGTH] [PEER]?}\\
+\# {\bf Parameters:}\\
+\# ---Device name. It may have alias suffix, separated by colon.\\
+\# ---Command: add, delete or stop.\\
+\# ---IP address, optionally followed by prefix length.\\
+\# ---Optional peer address for pointopoint interfaces.\\
+\# F.e. \verb|ifcfg eth0 193.233.7.90/24|
+
+\noindent\# This function determines, whether it is router or host.\\
+\# It returns 0, if the host is apparently not router.
+\end{flushleft}
+\begin{verbatim}
+CheckForwarding () {
+  local sbase fwd
+  sbase=/proc/sys/net/ipv4/conf
+  fwd=0
+  if [ -d $sbase ]; then
+    for dir in $sbase/*/forwarding; do
+      fwd=$[$fwd + `cat $dir`]
+    done
+  else
+    fwd=2
+  fi
+  return $fwd
+}
+\end{verbatim}
+\begin{flushleft}
+\# This function restarts Router Discovery.\\
+\end{flushleft}
+\begin{verbatim}
+RestartRDISC () {
+  killall -HUP rdisc || rdisc -fs
+}
+\end{verbatim}
+\begin{flushleft}
+\# Calculate ABC "natural" mask length\\
+\# Arg: \$1 = dotquad address
+\end{flushleft}
+\begin{verbatim}
+ABCMaskLen () {
+  local class;
+  class=${1%%.*}
+  if [ $class -eq 0 -o $class -ge 224 ]; then return 0
+  elif [ $class -ge 192 ]; then return 24
+  elif [ $class -ge 128 ]; then return 16
+  else  return 8 ; fi
+}
+\end{verbatim}
+
+
+\begin{flushleft}
+\# {\bf MAIN()}\\
+\#\\
+\# Strip alias suffix separated by colon.
+\end{flushleft}
+\begin{verbatim}
+label="label $1"
+ldev=$1
+dev=${1%:*}
+if [ "$dev" = "" -o "$1" = "help" ]; then
+  echo "Usage: ifcfg DEV [[add|del [ADDR[/LEN]] [PEER] | stop]" 1>&2
+  echo "       add - add new address" 1>&2
+  echo "       del - delete address" 1>&2
+  echo "       stop - completely disable IP" 1>&2
+  exit 1
+fi
+shift
+
+CheckForwarding
+fwd=$?
+\end{verbatim}
+\begin{flushleft}
+\# Parse command. If it is ``stop'', flush and exit.
+\end{flushleft}
+\begin{verbatim}
+deleting=0
+case "$1" in
+add) shift ;;
+stop)
+  if [ "$ldev" != "$dev" ]; then
+    echo "Cannot stop alias $ldev" 1>&2
+    exit 1;
+  fi
+  ip -4 addr flush dev $dev $label || exit 1
+  if [ $fwd -eq 0 ]; then RestartRDISC; fi
+  exit 0 ;;
+del*)
+  deleting=1; shift ;;
+*)
+esac
+\end{verbatim}
+\begin{flushleft}
+\# Parse prefix, split prefix length, separated by slash.
+\end{flushleft}
+\begin{verbatim}
+ipaddr=
+pfxlen=
+if [ "$1" != "" ]; then
+  ipaddr=${1%/*}
+  if [ "$1" != "$ipaddr" ]; then
+    pfxlen=${1#*/}
+  fi
+  if [ "$ipaddr" = "" ]; then
+    echo "$1 is bad IP address." 1>&2
+    exit 1
+  fi
+fi
+shift
+\end{verbatim}
+\begin{flushleft}
+\# If peer address is present, prefix length is 32.\\
+\# Otherwise, if prefix length was not given, guess it.
+\end{flushleft}
+\begin{verbatim}
+peer=$1
+if [ "$peer" != "" ]; then
+  if [ "$pfxlen" != "" -a "$pfxlen" != "32" ]; then
+    echo "Peer address with non-trivial netmask." 1>&2
+    exit 1
+  fi
+  pfx="$ipaddr peer $peer"
+else
+  if [ "$pfxlen" = "" ]; then
+    ABCMaskLen $ipaddr
+    pfxlen=$?
+  fi
+  pfx="$ipaddr/$pfxlen"
+fi
+if [ "$ldev" = "$dev" -a "$ipaddr" != "" ]; then
+  label=
+fi
+\end{verbatim}
+\begin{flushleft}
+\# If deletion was requested, delete the address and restart RDISC
+\end{flushleft}
+\begin{verbatim}
+if [ $deleting -ne 0 ]; then
+  ip addr del $pfx dev $dev $label || exit 1
+  if [ $fwd -eq 0 ]; then RestartRDISC; fi
+  exit 0
+fi
+\end{verbatim}
+\begin{flushleft}
+\# Start interface initialization.\\
+\#\\
+\# {\bf Step 0} --- enable device \verb|$dev|
+\end{flushleft}
+\begin{verbatim}
+if ! ip link set up dev $dev ; then
+  echo "Error: cannot enable interface $dev." 1>&2
+  exit 1
+fi
+if [ "$ipaddr" = "" ]; then exit 0; fi
+\end{verbatim}
+\begin{flushleft}
+\# {\bf Step 1} --- IP Duplicate Address Detection~\cite{RFC-DHCP}.\\
+\# Send two probes and wait for result for 3 seconds.\\
+\# If the interface opens slower f.e.\ due to long media detection,\\
+\# you want to increase the timeout.\\
+\end{flushleft}
+\begin{verbatim}
+if ! arping -q -c 2 -w 3 -D -I $dev $ipaddr ; then
+  echo "Error: some host already uses address $ipaddr on $dev." 1>&2
+  exit 1
+fi
+\end{verbatim}
+\begin{flushleft}
+\# OK, the address is unique. We may add it to the interface.\\
+\#\\
+\# {\bf Step 2} --- Configure the address on the interface.
+\end{flushleft}
+\begin{verbatim}
+if ! ip address add $pfx brd + dev $dev $label; then
+  echo "Error: failed to add $pfx on $dev." 1>&2
+  exit 1
+fi
+\end{verbatim}
+\noindent\# {\bf Step 3} --- Announce our presence on the link
+\begin{verbatim}
+arping -q -A -c 1 -I $dev $ipaddr
+noarp=$?
+( sleep 2 ;
+  arping -q -U -c 1 -I $dev $ipaddr ) >& /dev/null </dev/null &
+\end{verbatim}
+\begin{flushleft}
+\# {\bf Step 4} (optional) --- Add some control routes.\\
+\#\\
+\# 1. Prohibit link local multicast addresses.\\
+\# 2. Prohibit link local (alias, limited) broadcast.\\
+\# 3. Add default multicast route.
+\end{flushleft}
+\begin{verbatim}
+ip route add unreachable 224.0.0.0/24 >& /dev/null 
+ip route add unreachable 255.255.255.255 >& /dev/null
+if [ `ip link ls $dev | grep -c MULTICAST` -ge 1 ]; then
+  ip route add 224.0.0.0/4 dev $dev scope global >& /dev/null
+fi
+\end{verbatim}
+\begin{flushleft}
+\# {\bf Step 5} --- Add fallback default route with huge metric.\\
+\# If a proxy ARP server is present on the interface, we will be\\
+\# able to talk to all the Internet without further configuration.\\
+\# Do not make this step on router or if the device is not ARPable.\\
+\# because dead nexthop detection does not work on them.
+\end{flushleft}
+\begin{verbatim}
+if [ $fwd -eq 0 ]; then
+  if [ $noarp -eq 0 ]; then
+    ip ro append default dev $dev metric 30000 scope global
+  elif [ "$peer" != "" ]; then
+    if ping -q -c 2 -w 4 $peer ; then
+      ip ro append default via $peer dev $dev metric 30001
+    fi
+  fi
+  RestartRDISC
+fi
+
+exit 0
+\end{verbatim}
+\begin{flushleft}
+\# End of {\bf MAIN()}
+\end{flushleft}
+
+
+\end{document}
diff --git a/iproute2/doc/ip-tunnels.tex b/iproute2/doc/ip-tunnels.tex
new file mode 100644
index 0000000..0a8c930
--- /dev/null
+++ b/iproute2/doc/ip-tunnels.tex
@@ -0,0 +1,469 @@
+\documentstyle[12pt,twoside]{article}
+\def\TITLE{Tunnels over IP}
+\input preamble
+\begin{center}
+\Large\bf Tunnels over IP in Linux-2.2
+\end{center}
+
+
+\begin{center}
+{ \large Alexey~N.~Kuznetsov } \\
+\em Institute for Nuclear Research, Moscow \\
+\verb|kuznet@ms2.inr.ac.ru| \\
+\rm March 17, 1999
+\end{center}
+
+\vspace{5mm}
+
+\tableofcontents
+
+
+\section{Instead of introduction: micro-FAQ.}
+
+\begin{itemize}
+
+\item
+Q: In linux-2.0.36 I used:
+\begin{verbatim} 
+    ifconfig tunl1 10.0.0.1 pointopoint 193.233.7.65
+\end{verbatim} 
+to create tunnel. It does not work in 2.2.0!
+
+A: You are right, it does not work. The command written above is split to two commands.
+\begin{verbatim}
+    ip tunnel add MY-TUNNEL mode ipip remote 193.233.7.65
+\end{verbatim} 
+will create tunnel device with name \verb|MY-TUNNEL|. Now you may configure
+it with:
+\begin{verbatim} 
+    ifconfig MY-TUNNEL 10.0.0.1
+\end{verbatim} 
+Certainly, if you prefer name \verb|tunl1| to \verb|MY-TUNNEL|,
+you still may use it.
+
+\item
+Q: In linux-2.0.36 I used:
+\begin{verbatim} 
+    ifconfig tunl0 10.0.0.1
+    route add -net 10.0.0.0 gw 193.233.7.65 dev tunl0
+\end{verbatim} 
+to tunnel net 10.0.0.0 via router 193.233.7.65. It does not
+work in 2.2.0! Moreover, \verb|route| prints a funny error sort of
+``network unreachable'' and after this I found a strange direct route
+to 10.0.0.0 via \verb|tunl0| in routing table.
+
+A: Yes, in 2.2 the rule that {\em normal} gateway must reside on directly
+connected network has not any exceptions. You may tell kernel, that
+this particular route is {\em abnormal}:
+\begin{verbatim} 
+  ifconfig tunl0 10.0.0.1 netmask 255.255.255.255
+  ip route add 10.0.0.0/8 via 193.233.7.65 dev tunl0 onlink
+\end{verbatim}
+Note keyword \verb|onlink|, it is the magic key that orders kernel
+not to check for consistency of gateway address.
+Probably, after this explanation you have already guessed another method
+to cheat kernel:
+\begin{verbatim} 
+  ifconfig tunl0 10.0.0.1 netmask 255.255.255.255
+  route add -host 193.233.7.65 dev tunl0
+  route add -net 10.0.0.0 netmask 255.0.0.0 gw 193.233.7.65
+  route del -host 193.233.7.65 dev tunl0
+\end{verbatim}
+Well, if you like such tricks, nobody may prohibit you to use them.
+Only do not forget
+that between \verb|route add| and \verb|route del| host 193.233.7.65 is
+unreachable.
+
+\item
+Q: In 2.0.36 I used to load \verb|tunnel| device module and \verb|ipip| module.
+I cannot find any \verb|tunnel| in 2.2!
+
+A: Linux-2.2 has single module \verb|ipip| for both directions of tunneling
+and for all IPIP tunnel devices.
+
+\item
+Q: \verb|traceroute| does not work over tunnel! Well, stop... It works,
+     only skips some number of hops.
+
+A: Yes. By default tunnel driver copies \verb|ttl| value from
+inner packet to outer one. It means that path traversed by tunneled
+packets to another endpoint is not hidden. If you dislike this, or if you
+are going to use some routing protocol expecting that packets
+with ttl 1 will reach peering host (f.e.\ RIP, OSPF or EBGP)
+and you are not afraid of
+tunnel loops, you may append option \verb|ttl 64|, when creating tunnel
+with \verb|ip tunnel add|.
+
+\item
+Q: ... Well, list of things, which 2.0 was able to do finishes.
+
+\end{itemize}
+
+\paragraph{Summary of differences between 2.2 and 2.0.}
+
+\begin{itemize}
+
+\item {\bf In 2.0} you could compile tunnel device into kernel
+	and got set of 4 devices \verb|tunl0| ... \verb|tunl3| or,
+	alternatively, compile it as module and load new module
+	for each new tunnel. Also, module \verb|ipip| was necessary
+	to receive tunneled packets.
+
+      {\bf 2.2} has {\em one\/} module \verb|ipip|. Loading it you get base
+	tunnel device \verb|tunl0| and another tunnels may be created with command
+	\verb|ip tunnel add|. These new devices may have arbitrary names.
+
+
+\item {\bf In 2.0} you set remote tunnel endpoint address with
+	the command \verb|ifconfig| ... \verb|pointopoint A|.
+
+	{\bf In 2.2} this command has the same semantics on all
+	the interfaces, namely it sets not tunnel endpoint,
+	but address of peering host, which is directly reachable
+	via this tunnel,
+	rather than via Internet. Actual tunnel endpoint address \verb|A|
+	should be set with \verb|ip tunnel add ... remote A|.
+
+\item {\bf In 2.0} you create tunnel routes with the command:
+\begin{verbatim}
+    route add -net 10.0.0.0 gw A dev tunl0
+\end{verbatim}
+
+	{\bf 2.2} interprets this command equally for all device
+	kinds and gateway is required to be directly reachable via this tunnel,
+	rather than via Internet. You still may use \verb|ip route add ... onlink|
+	to override this behaviour.
+
+\end{itemize}
+
+
+\section{Tunnel setup: basics}
+
+Standard Linux-2.2 kernel supports three flavor of tunnels,
+listed in the following table:
+\vspace{2mm}
+
+\begin{tabular}{lll}
+\vrule depth 0.8ex width 0pt\relax
+Mode & Description  & Base device \\
+ipip & IP over IP & tunl0 \\
+sit & IPv6 over IP & sit0 \\
+gre & ANY over GRE over IP & gre0
+\end{tabular}
+
+\vspace{2mm}
+
+\noindent All the kinds of tunnels are created with one command:
+\begin{verbatim}
+  ip tunnel add <NAME> mode <MODE> [ local <S> ] [ remote <D> ]
+\end{verbatim}
+
+This command creates new tunnel device with name \verb|<NAME>|.
+The \verb|<NAME>| is an arbitrary string. Particularly,
+it may be even \verb|eth0|. The rest of parameters set
+different tunnel characteristics.
+
+\begin{itemize}
+
+\item
+\verb|mode <MODE>| sets tunnel mode. Three modes are available now
+	\verb|ipip|, \verb|sit| and \verb|gre|.
+
+\item
+\verb|remote <D>| sets remote endpoint of the tunnel to IP
+	address \verb|<D>|.
+\item
+\verb|local <S>| sets fixed local address for tunneled
+	packets. It must be an address on another interface of this host.
+
+\end{itemize}
+
+\let\thefootnote\oldthefootnote
+
+Both \verb|remote| and \verb|local| may be omitted. In this case we
+say that they are zero or wildcard. Two tunnels of one mode cannot
+have the same \verb|remote| and \verb|local|. Particularly it means
+that base device or fallback tunnel cannot be replicated.\footnote{
+This restriction is relaxed for keyed GRE tunnels.}
+
+Tunnels are divided to two classes: {\bf pointopoint} tunnels, which
+have some not wildcard \verb|remote| address and deliver all the packets
+to this destination, and {\bf NBMA} (i.e. Non-Broadcast Multi-Access) tunnels,
+which have no \verb|remote|. Particularly, base devices (f.e.\ \verb|tunl0|)
+are NBMA, because they have neither \verb|remote| nor
+\verb|local| addresses.
+
+
+After tunnel device is created you should configure it as you did
+it with another devices. Certainly, the configuration of tunnels has
+some features related to the fact that they work over existing Internet
+routing infrastructure and simultaneously create new virtual links,
+which changes this infrastructure. The danger that not enough careful
+tunnel setup will result in formation of tunnel loops,
+collapse of routing or flooding network with exponentially
+growing number of tunneled fragments is very real.
+
+
+Protocol setup on pointopoint tunnels does not differ of configuration
+of another devices. You should set a protocol address with \verb|ifconfig|
+and add routes with \verb|route| utility.
+
+NBMA tunnels are different. To route something via NBMA tunnel
+you have to explain to driver, where it should deliver packets to.
+The only way to make it is to create special routes with gateway
+address pointing to desired endpoint. F.e.\ 
+\begin{verbatim}
+    ip route add 10.0.0.0/24 via <A> dev tunl0 onlink
+\end{verbatim}
+It is important to use option \verb|onlink|, otherwise
+kernel will refuse request to create route via gateway not directly
+reachable over device \verb|tunl0|. With IPv6 the situation is much simpler:
+when you start device \verb|sit0|, it automatically configures itself
+with all IPv4 addresses mapped to IPv6 space, so that all IPv4
+Internet is {\em really reachable} via \verb|sit0|! Excellent, the command
+\begin{verbatim}
+    ip route add 3FFE::/16 via ::193.233.7.65 dev sit0
+\end{verbatim}
+will route \verb|3FFE::/16| via \verb|sit0|, sending all the packets
+destined to this prefix to 193.233.7.65.
+
+\section{Tunnel setup: options}
+
+Command \verb|ip tunnel add| has several additional options.
+\begin{itemize}
+
+\item \verb|ttl N| --- set fixed TTL \verb|N| on tunneled packets.
+	\verb|N| is number in the range 1--255. 0 is special value,
+	meaning that packets inherit TTL value. 
+		Default value is: \verb|inherit|.
+
+\item \verb|tos T| --- set fixed tos \verb|T| on tunneled packets.
+		Default value is: \verb|inherit|.
+
+\item \verb|dev DEV| --- bind tunnel to device \verb|DEV|, so that
+	tunneled packets will be routed only via this device and will
+	not be able to escape to another device, when route to endpoint changes.
+
+\item \verb|nopmtudisc| --- disable Path MTU Discovery on this tunnel.
+	It is enabled by default. Note that fixed ttl is incompatible
+	with this option: tunnels with fixed ttl always make pmtu discovery.
+
+\end{itemize}
+
+\verb|ipip| and \verb|sit| tunnels have no more options. \verb|gre|
+tunnels are more complicated:
+
+\begin{itemize}
+
+\item \verb|key K| --- use keyed GRE with key \verb|K|. \verb|K| is
+	either number or IP address-like dotted quad.
+
+\item \verb|csum| --- checksum tunneled packets.
+
+\item \verb|seq| --- serialize packets.
+\begin{NB}
+	I think this option does not
+	work. At least, I did not test it, did not debug it and
+	even do not understand,	how it is supposed to work and for what
+	purpose Cisco planned to use it.
+\end{NB}
+
+\end{itemize}
+
+
+Actually, these GRE options can be set separately for input and
+output directions by prefixing corresponding keywords with letter
+\verb|i| or \verb|o|. F.e.\ \verb|icsum| orders to accept only
+packets with correct checksum and \verb|ocsum| means, that
+our host will calculate and send checksum.
+
+Command \verb|ip tunnel add| is not the only operation,
+which can be made with tunnels. Certainly, you may get short help page
+with:
+\begin{verbatim}
+    ip tunnel help
+\end{verbatim}
+
+Besides that, you may view list of installed tunnels with the help of command:
+\begin{verbatim}
+    ip tunnel ls
+\end{verbatim}
+Also you may look at statistics:
+\begin{verbatim}
+    ip -s tunnel ls Cisco
+\end{verbatim}
+where \verb|Cisco| is name of tunnel device. Command
+\begin{verbatim}
+    ip tunnel del Cisco
+\end{verbatim}
+destroys tunnel \verb|Cisco|. And, finally,
+\begin{verbatim}
+    ip tunnel change Cisco mode sit local ME remote HE ttl 32
+\end{verbatim}
+changes its parameters.
+
+\section{Differences 2.2 and 2.0 tunnels revisited.}
+
+Now we can discuss more subtle differences between tunneling in 2.0
+and 2.2.
+
+\begin{itemize}
+
+\item In 2.0 all tunneled packets were received promiscuously
+as soon as you loaded module \verb|ipip|. 2.2 tries to select the best
+tunnel device and packet looks as received on this. F.e.\ if host
+received \verb|ipip| packet from host \verb|D| destined to our
+local address \verb|S|, kernel searches for matching tunnels
+in order:
+
+\begin{tabular}{ll}
+1 & \verb|remote| is \verb|D| and \verb|local| is \verb|S| \\
+2 & \verb|remote| is \verb|D| and \verb|local| is wildcard \\
+3 & \verb|remote| is wildcard and \verb|local| is \verb|S| \\
+4 & \verb|tunl0|
+\end{tabular}
+
+If tunnel exists, but it is not in \verb|UP| state, the tunnel is ignored.
+Note, that if \verb|tunl0| is \verb|UP| it receives all the IPIP packets,
+not acknowledged by more specific tunnels.
+Be careful, it means that without carefully installed firewall rules
+anyone on the Internet may inject to your network any packets with
+source addresses indistinguishable from local ones. It is not so bad idea
+to design tunnels in the way enforcing maximal route symmetry
+and to enable reversed path filter (\verb|rp_filter| sysctl option) on
+tunnel devices.
+
+\item In 2.2 you can monitor and debug tunnels with \verb|tcpdump|.
+F.e.\ \verb|tcpdump| \verb|-i Cisco| \verb|-nvv| will dump packets,
+which kernel output, via tunnel \verb|Cisco| and the packets received on it
+from kernel viewpoint.
+
+\end{itemize}
+
+
+\section{Linux and Cisco IOS tunnels.}
+
+Among another tunnels Cisco IOS supports IPIP and GRE.
+Essentially, Cisco setup is subset of options, available for Linux.
+Let us consider the simplest example:
+
+\begin{verbatim}
+interface Tunnel0
+ tunnel mode gre ip
+ tunnel source 10.10.14.1
+ tunnel destination 10.10.13.2
+\end{verbatim}
+
+
+This command set translates to:
+
+\begin{verbatim}
+    ip tunnel add Tunnel0 \
+        mode gre \
+        local 10.10.14.1 \
+        remote 10.10.13.2
+\end{verbatim}
+
+Any questions? No questions.
+
+\section{Interaction IPIP tunnels and DVMRP.}
+
+DVMRP exploits IPIP tunnels to route multicasts via Internet.
+\verb|mrouted| creates
+IPIP tunnels listed in its configuration file automatically.
+From kernel and user viewpoints there are no differences between
+tunnels, created in this way, and tunnels created by \verb|ip tunnel|.
+I.e.\ if \verb|mrouted| created some tunnel, it may be used to
+route unicast packets, provided appropriate routes are added.
+And vice versa, if administrator has already created a tunnel,
+it will be reused by \verb|mrouted|, if it requests DVMRP
+tunnel with the same local and remote addresses.
+
+Do not wonder, if your manually configured tunnel is
+destroyed, when mrouted exits.
+
+
+\section{Broadcast GRE ``tunnels''.}
+
+It is possible to set \verb|remote| for GRE tunnel to a multicast
+address. Such tunnel becomes {\bf broadcast} tunnel (though word
+tunnel is not quite appropriate in this case, it is rather virtual network).
+\begin{verbatim}
+  ip tunnel add Universe local 193.233.7.65 \
+                         remote 224.66.66.66 ttl 16
+  ip addr add 10.0.0.1/16 dev Universe
+  ip link set Universe up
+\end{verbatim}
+This tunnel is true broadcast network and broadcast packets are
+sent to multicast group 224.66.66.66. By default such tunnel starts
+to resolve both IP and IPv6 addresses via ARP/NDISC, so that
+if multicast routing is supported in surrounding network, all GRE nodes
+will find one another automatically and will form virtual Ethernet-like
+broadcast network. If multicast routing does not work, it is unpleasant
+but not fatal flaw. The tunnel becomes NBMA rather than broadcast network.
+You may disable dynamic ARPing by:
+\begin{verbatim}
+  echo 0 > /proc/sys/net/ipv4/neigh/Universe/mcast_solicit
+\end{verbatim}
+and to add required information to ARP tables manually:
+\begin{verbatim}
+  ip neigh add 10.0.0.2 lladdr 128.6.190.2 dev Universe nud permanent
+\end{verbatim}
+In this case packets sent to 10.0.0.2 will be encapsulated in GRE
+and sent to 128.6.190.2. It is possible to facilitate address resolution
+using methods typical for another NBMA networks f.e.\ to start user
+level \verb|arpd| daemon, which will maintain database of hosts attached
+to GRE virtual network or ask for information
+dedicated ARP or NHRP server.
+
+
+Actually, such setup is the most natural for tunneling,
+it is really flexible, scalable and easily managable, so that
+it is strongly recommended to be used with GRE tunnels instead of ugly
+hack with NBMA mode and \verb|onlink| modifier. Unfortunately,
+by historical reasons broadcast mode is not supported by IPIP tunnels,
+but this probably will change in future.
+
+
+
+\section{Traffic control issues.}
+
+Tunnels are devices, hence all the power of Linux traffic control
+applies to them. The simplest (and the most useful in practice)
+example is limiting tunnel bandwidth. The following command:
+\begin{verbatim}
+    tc qdisc add dev tunl0 root tbf \
+        rate 128Kbit burst 4K limit 10K
+\end{verbatim}
+will limit tunneled traffic to 128Kbit with maximal burst size of 4K
+and queuing not more than 10K.
+
+However, you should remember, that tunnels are {\em virtual} devices
+implemented in software and true queue management is impossible for them
+just because they have no queues. Instead, it is better to create classes
+on real physical interfaces and to map tunneled packets to them.
+In general case of dynamic routing you should create such classes
+on all outgoing interfaces, or, alternatively,
+to use option \verb|dev DEV| to bind tunnel to a fixed physical device.
+In the last case packets will be routed only via specified device
+and you need to setup corresponding classes only on it.
+Though you have to pay for this convenience,
+if routing will change, your tunnel will fail.
+
+Suppose that CBQ class \verb|1:ABC| has been created on device \verb|eth0| 
+specially for tunnel \verb|Cisco| with endpoints \verb|S| and \verb|D|.
+Now you can select IPIP packets with addresses \verb|S| and \verb|D|
+with some classifier and map them to class \verb|1:ABC|. F.e.\ 
+it is easy to make with \verb|rsvp| classifier:
+\begin{verbatim}
+    tc filter add dev eth0 pref 100 proto ip rsvp \
+        session D ipproto ipip filter S \
+        classid 1:ABC
+\end{verbatim}
+
+If you want to make more detailed classification of sub-flows
+transmitted via tunnel, you can build CBQ subtree,
+rooted at \verb|1:ABC| and attach to subroot set of rules parsing
+IPIP packets more deeply.
+
+\end{document}
diff --git a/iproute2/doc/nstat.sgml b/iproute2/doc/nstat.sgml
new file mode 100644
index 0000000..48cacc6
--- /dev/null
+++ b/iproute2/doc/nstat.sgml
@@ -0,0 +1,110 @@
+<!doctype linuxdoc system>
+
+<article>
+
+<title>NSTAT, IFSTAT and RTACCT Utilities
+<author>Alexey Kuznetsov, <tt/kuznet@ms2.inr.ac.ru/
+<date>some_negative_number, 20 Sep 2001
+<abstract>
+<tt/nstat/, <tt/ifstat/ and <tt/rtacct/ are simple tools helping
+to monitor kernel snmp counters and network interface statistics.
+</abstract>
+
+<p> These utilities are very similar, so that I describe
+them simultaneously, using name <tt/Xstat/ in the places which apply
+to all of them.
+
+<p>The format of the command is:
+
+<tscreen><verb>
+       Xstat [ OPTIONS ] [ PATTERN [ PATTERN ... ] ]
+</verb></tscreen>
+
+<p>
+<tt/PATTERN/ is shell style pattern, selecting identifier
+of SNMP variables or interfaces to show. Variable is displayed
+if one of patterns matches its name. If no patterns are given,
+<tt/Xstat/ assumes that user wants to see all the variables.  
+
+<p> <tt/OPTIONS/ is list of single letter options, using common unix
+conventions.
+
+<itemize>
+<item><tt/-h/  - show help page
+<item><tt/-?/  - the same, of course
+<item><tt/-v/, <tt/-V/  - print version of <tt/Xstat/ and exit
+<item><tt/-z/ - dump zero counters too. By default they are not shown.
+<item><tt/-a/ - dump absolute values of counters. By default <tt/Xstat/
+                calculates increments since the previous use.
+<item><tt/-s/ - do not update history, so that the next time you will
+                see counters including values accumulated to the moment
+                of this measurement too.
+<item><tt/-n/ - do not display anything, only update history.
+<item><tt/-r/ - reset history.
+<item><tt/-d INTERVAL/ - <tt/Xstat/ is run in daemon mode collecting
+                statistics. <tt/INTERVAL/ is interval between measurements
+                in seconds.
+<item><tt/-t INTERVAL/ - time interval to average rates. Default value
+                is 60 seconds. 
+<item><tt/-e/ - display extended information about errors (<tt/ifstat/ only).
+</itemize>
+
+<p>
+History is just dump saved in file <tt>/tmp/.Xstat.uUID</tt>
+or in file given by environment variables <tt/NSTAT_HISTORY/,
+<tt/IFSTAT_HISTORY/ and <tt/RTACCT_HISTORY/.
+Each time when you use <tt/Xstat/ values there are updated.
+If you use patterns, only the values which you _really_ see
+are updated. If you want to skip an unintersting period,
+use option <tt/-n/, or just output to <tt>/dev/null</tt>.
+
+<p>
+<tt/Xstat/ understands when history is invalidated by system reboot
+or source of information switched between different instances
+of daemonic <tt/Xstat/ and kernel SNMP tables and does not
+use invalid history.
+
+<p> Beware, <tt/Xstat/ will not produce sane output,
+when many processes use it simultaneously. If several processes
+under single user need this utility they should use environment
+variables to put their history in safe places
+or to use it with options <tt/-a -s/.
+
+<p>
+Well, that's all. The utility is very simple, but nevertheless
+very handy.
+
+<p> <bf/Output of XSTAT/
+<p> The first line of output is <tt/#/ followed by identifier
+of source of information, it may be word <tt/kernel/, when <tt/Xstat/
+gets information from kernel or some dotted decimal number followed
+by parameters, when it obtains information from running <tt/Xstat/ daemon.
+
+<p>In the case of <tt/nstat/ the rest of output consists of three columns:
+SNMP MIB identifier,
+its value (or increment since previous measurement) and average
+rate of increase of the counter per second. <tt/ifstat/ outputs
+interface name followed by pairs of counter and rate of its change.
+
+<p> <bf/Daemonic Xstat/
+<p> <tt/Xstat/ may be started as daemon by any user. This makes sense
+to avoid wrapped counters and to obtain reasonable long counters
+for large time. Also <tt/Xstat/ daemon calculates average rates.
+For the first goal sampling interval (option <tt/-d/) may be large enough,
+f.e. for gigabit rates byte counters overflow not more frequently than
+each 40 seconds and you may select interval of 20 seconds.
+From the other hand, when <tt/Xstat/ is used for estimating rates
+interval should be less than averaging period (option <tt/-t/), otherwise
+estimation loses in quality.
+
+Client <tt/Xstat/, before trying to get information from the kernel,
+contacts daemon started by this user, then it tries system wide
+daemon, which is supposed to be started by superuser. And only if
+none of them replied it gets information from kernel.
+
+<p> <bf/Environment/
+<p> <tt/NSTAT_HISTORY/ - name of history file for <tt/nstat/.
+<p> <tt/IFSTAT_HISTORY/ - name of history file for <tt/ifstat/.
+<p> <tt/RTACCT_HISTORY/ - name of history file for <tt/rtacct/.
+
+</article>
diff --git a/iproute2/doc/preamble.tex b/iproute2/doc/preamble.tex
new file mode 100644
index 0000000..80ca508
--- /dev/null
+++ b/iproute2/doc/preamble.tex
@@ -0,0 +1,26 @@
+\textwidth   6.0in
+\textheight  8.5in
+
+\input SNAPSHOT
+
+\pagestyle{myheadings}
+\markboth{\protect\TITLE}{}
+\markright{{\protect\sc iproute2-ss\Draft}}
+
+% To print it in compact form: both sides on one sheet (psnup -2)
+\evensidemargin=\oddsidemargin
+
+\newenvironment{NB}{\bgroup \vskip 1mm\leftskip 1cm \footnotesize \noindent NB.
+}{\par\egroup \vskip 1mm}
+
+\def\threeonly{[2.3.15+ only] }
+
+\begin{document}
+
+\makeatletter
+\renewcommand{\@oddhead}{{\protect\sc iproute2-ss\Draft} \hfill \protect\arabic{page}}
+\makeatother
+\let\oldthefootnote\thefootnote
+\def\thefootnote{}
+\footnotetext{Copyright \copyright~1999 A.N.Kuznetsov}
+
diff --git a/iproute2/doc/rtstat.sgml b/iproute2/doc/rtstat.sgml
new file mode 100644
index 0000000..07391c3
--- /dev/null
+++ b/iproute2/doc/rtstat.sgml
@@ -0,0 +1,52 @@
+<!doctype linuxdoc system>
+
+<article>
+
+<title>RTACCT Utility
+<author>Robert Olsson
+<date>some_negative_number, 20 Dec 2001
+
+<p>
+Here is some code for monitoring the route cache. For systems handling high
+network load, servers, routers, firewalls etc the route cache and its garbage
+collection is crucial. Linux has a solid implementation.
+
+<p>
+The kernel patch (not required since linux-2.4.7) adds statistics counters
+from route cache process into 
+/proc/net/rt_cache_stat. A companion user mode program presents the statistics
+in a vmstat or iostat manner. The ratio between cache hits and misses gives 
+the flow length.
+
+<p>
+Hopefully it can help understanding performance and DoS and other related
+issues.
+
+<p> An URL where newer versions of this utility can be (probably) found
+is ftp://robur.slu.se/pub/Linux/net-development/rt_cache_stat/
+
+
+<p><bf/Description/
+
+<p>The format of the command is:
+
+<tscreen><verb>
+       rtstat [ OPTIONS ]
+</verb></tscreen>
+
+<p> <tt/OPTIONS/ are:
+
+<itemize>
+
+<item><tt/-h/, <tt/-help/ - show help page and version of the utility.
+
+<item><tt/-i INTERVAL/ - interval between snapshots, default value is
+2 seconds.
+
+<item><tt/-s NUMBER/ - whether to print header line. 0 inhibits header line,
+1 prescribes to print it once and 2 (this is default setting) forces header
+line each 20 lines. 
+
+</itemize>
+
+</article>
diff --git a/iproute2/doc/ss.sgml b/iproute2/doc/ss.sgml
new file mode 100644
index 0000000..3024b57
--- /dev/null
+++ b/iproute2/doc/ss.sgml
@@ -0,0 +1,525 @@
+<!doctype linuxdoc system>
+
+<article>
+
+<title>SS Utility: Quick Intro
+<author>Alexey Kuznetsov, <tt/kuznet@ms2.inr.ac.ru/
+<date>some_negative_number, 20 Sep 2001
+<abstract>
+<tt/ss/ is one another utility to investigate sockets.
+Functionally it is NOT better than <tt/netstat/ combined
+with some perl/awk scripts and though it is surely faster
+it is not enough to make it much better. :-)
+So, stop reading this now and do not waste your time.
+Well, certainly, it proposes some functionality, which current
+netstat is still not able to do, but surely will soon.
+</abstract>
+
+<sect>Why?
+
+<p> <tt>/proc</tt> interface is inadequate, unfortunately.
+When amount of sockets is enough large, <tt/netstat/ or even
+plain <tt>cat /proc/net/tcp/</tt> cause nothing but pains and curses.
+In linux-2.4 the desease became worse: even if amount
+of sockets is small reading <tt>/proc/net/tcp/</tt> is slow enough.
+
+This utility presents a new approach, which is supposed to scale
+well. I am not going to describe technical details here and
+will concentrate on description of the command.
+The only important thing to say is that it is not so bad idea
+to load module <tt/tcp_diag/, which can be found in directory
+<tt/Modules/ of <tt/iproute2/. If you do not make this <tt/ss/
+will work, but it falls back to <tt>/proc</tt> and becomes slow
+like <tt/netstat/, well, a bit faster yet (see section "Some numbers"). 
+
+<sect>Old news
+
+<p>
+In the simplest form <tt/ss/ is equivalent to netstat
+with some small deviations.
+
+<itemize>
+<item><tt/ss -t -a/ dumps all TCP sockets
+<item><tt/ss -u -a/ dumps all UDP sockets
+<item><tt/ss -w -a/ dumps all RAW sockets
+<item><tt/ss -x -a/ dumps all UNIX sockets
+</itemize>
+
+<p>
+Option <tt/-o/ shows TCP timers state.
+Option <tt/-e/ shows some extended information.
+Etc. etc. etc. Seems, all the options of netstat related to sockets
+are supported. Though not AX.25 and other bizarres. :-)
+If someone wants, he can make support for decnet and ipx.
+Some rudimentary support for them is already present in iproute2 libutils,
+and I will be glad to see these new members.
+
+<p>
+However, standard functionality is a bit different:
+
+<p>
+The first: without option <tt/-a/ sockets in states
+<tt/TIME-WAIT/ and <tt/SYN-RECV/ are skipped too.
+It is more reasonable default, I think.
+
+<p>
+The second: format of UNIX sockets is different. It coincides
+with tcp/udp. Though standard kernel still does not allow to
+see write/read queues and peer address of connected UNIX sockets,
+the patch doing this exists.
+
+<p>
+The third: default is to dump only TCP sockets, rather than all of the types.
+
+<p>
+The next: by default it does not resolve numeric host addresses (like <tt/ip/)!
+Resolving is enabled with option <tt/-r/. Service names, usually stored
+in local files, are resolved by default. Also, if service database
+does not contain references to a port, <tt/ss/ queries system
+<tt/rpcbind/. RPC services are prefixed with <tt/rpc./
+Resolution of services may be suppressed with option <tt/-n/.
+
+<p>
+It does not accept "long" options (I dislike them, sorry).
+So, address family is given with family identifier following
+option <tt/-f/ to be algined to iproute2 conventions.
+Mostly, it is to allow option parser to parse
+addresses correctly, but as side effect it really limits dumping
+to sockets supporting only given family. Option <tt/-A/ followed
+by list of socket tables to dump is also supported.
+Logically, id of socket table is different of _address_ family, which is
+another point of incompatibility. So, id is one of
+<tt/all/, <tt/tcp/, <tt/udp/,
+<tt/raw/, <tt/inet/, <tt/unix/, <tt/packet/, <tt/netlink/. See?
+Well, <tt/inet/ is just abbreviation for <tt/tcp|udp|raw/
+and it is not difficult to guess that <tt/packet/ allows
+to look at packet sockets. Actually, there are also some other abbreviations,
+f.e. <tt/unix_dgram/ selects only datagram UNIX sockets.
+
+<p>
+The next: well, I still do not know. :-)
+
+
+
+
+<sect>Time to talk about new functionality.
+
+<p>It is builtin filtering of socket lists. 
+
+<sect1> Filtering by state.
+
+<p>
+<tt/ss/ allows to filter socket states, using keywords
+<tt/state/ and <tt/exclude/, followed by some state
+identifier.
+
+<p>
+State identifier are standard TCP state names (not listed,
+they are useless for you if you already do not know them)
+or abbreviations:
+
+<itemize>
+<item><tt/all/        - for all the states
+<item><tt/bucket/     - for TCP minisockets (<tt/TIME-WAIT|SYN-RECV/)
+<item><tt/big/	      - all except for minisockets
+<item><tt/connected/  - not closed and not listening
+<item><tt/synchronized/ - connected and not <tt/SYN-SENT/
+</itemize>
+
+<p>
+   F.e. to dump all tcp sockets except <tt/SYN-RECV/:
+
+<tscreen><verb>
+   ss exclude SYN-RECV
+</verb></tscreen>
+
+<p>
+   If neither <tt/state/ nor <tt/exclude/ directives
+   are present,
+   state filter defaults to <tt/all/ with option <tt/-a/
+   or to <tt/all/,
+   excluding listening, syn-recv, time-wait and closed sockets.
+
+<sect1> Filtering by addresses and ports.
+
+<p>
+Option list may contain address/port filter.
+It is boolean expression which consists of boolean operation
+<tt/or/, <tt/and/, <tt/not/ and predicates. 
+Actually, all the flavors of names for boolean operations are eaten:
+<tt/&amp/, <tt/&amp&amp/, <tt/|/, <tt/||/, <tt/!/, but do not forget
+about special sense given to these symbols by unix shells and escape
+them correctly, when used from command line.
+
+<p>
+Predicates may be of the folowing kinds:
+
+<itemize>
+<item>A. Address/port match, where address is checked against mask
+      and port is either wildcard or exact. It is one of:
+ 
+<tscreen><verb>
+	dst prefix:port
+	src prefix:port
+	src unix:STRING
+	src link:protocol:ifindex
+	src nl:channel:pid
+</verb></tscreen>
+
+      Both prefix and port may be absent or replaced with <tt/*/,
+      which means wildcard. UNIX socket use more powerful scheme
+      matching to socket names by shell wildcards. Also, prefixes
+      unix: and link: may be omitted, if address family is evident
+      from context (with option <tt/-x/ or with <tt/-f unix/
+      or with <tt/unix/ keyword) 
+
+<p>
+      F.e.
+
+<tscreen><verb>
+	dst 10.0.0.1
+	dst 10.0.0.1:
+	dst 10.0.0.1/32:
+	dst 10.0.0.1:*
+</verb></tscreen>
+   are equivalent and mean socket connected to
+	                 any port on host 10.0.0.1
+
+<tscreen><verb>
+	dst 10.0.0.0/24:22
+</verb></tscreen>
+   sockets connected to port 22 on network
+                          10.0.0.0...255.
+
+<p>
+      Note that port separated of address with colon, which creates
+      troubles with IPv6 addresses. Generally, we interpret the last
+      colon as splitting port. To allow to give IPv6 addresses,
+      trick like used in IPv6 HTTP URLs may be used:
+
+<tscreen><verb>
+      dst [::1]
+</verb></tscreen>
+       are sockets connected to ::1 on any port
+
+<p>
+      Another way is <tt/dst ::1/128/. / helps to understand that
+      colon is part of IPv6 address.
+
+<p>
+      Now we can add another alias for <tt/dst 10.0.0.1/:
+      <tt/dst [10.0.0.1]/. :-)
+
+<p>   Address may be a DNS name. In this case all the addresses are looked
+      up (in all the address families, if it is not limited by option <tt/-f/
+      or special address prefix <tt/inet:/, <tt/inet6/) and resulting
+      expression is <tt/or/ over all of them.  
+
+<item>   B. Port expressions:
+<tscreen><verb>
+      dport &gt= :1024
+      dport != :22
+      sport &lt :32000
+</verb></tscreen>
+      etc.
+
+      All the relations: <tt/&lt/, <tt/&gt/, <tt/=/, <tt/>=/, <tt/=/, <tt/==/,
+      <tt/!=/, <tt/eq/, <tt/ge/, <tt/lt/, <tt/ne/...
+      Use variant which you like more, but not forget to escape special
+      characters when typing them in command line. :-) 
+
+      Note that port number syntactically coincides to the case A!
+      You may even add an IP address, but it will not participate
+      incomparison, except for <tt/==/ and <tt/!=/, which are equivalent
+      to corresponding predicates of type A. F.e.
+<p>
+<tt/dst 10.0.0.1:22/
+    is equivalent to  <tt/dport eq 10.0.0.1:22/
+      and
+      <tt/not dst 10.0.0.1:22/     is equivalent to
+ <tt/dport neq 10.0.0.1:22/
+
+<item>C. Keyword <tt/autobound/. It matches to sockets bound automatically
+      on local system.
+
+</itemize>
+
+
+<sect> Examples
+
+<p>
+<itemize>
+<item>1. List all the tcp sockets in state <tt/FIN-WAIT-1/ for our apache
+   to network 193.233.7/24 and look at their timers:
+
+<tscreen><verb>
+   ss -o state fin-wait-1 \( sport = :http or sport = :https \) \
+                          dst 193.233.7/24
+</verb></tscreen>
+
+   Oops, forgot to say that missing logical operation is
+   equivalent to <tt/and/.
+
+<item> 2. Well, now look at the rest...
+
+<tscreen><verb>
+   ss -o excl fin-wait-1
+   ss state fin-wait-1 \( sport neq :http and sport neq :https \) \
+                       or not dst 193.233.7/24
+</verb></tscreen>
+
+   Note that we have to do _two_ calls of ss to do this.
+   State match is always anded to address/port match.
+   The reason for this is purely technical: ss does fast skip of
+   not matching states before parsing addresses and I consider the
+   ability to skip fastly gobs of time-wait and syn-recv sockets
+   as more important than logical generality.
+
+<item> 3. So, let's look at all our sockets using autobound ports:
+
+<tscreen><verb>
+   ss -a -A all autobound
+</verb></tscreen>
+
+
+<item> 4. And eventually find all the local processes connected
+   to local X servers:
+
+<tscreen><verb>
+   ss -xp dst "/tmp/.X11-unix/*"
+</verb></tscreen>
+
+   Pardon, this does not work with current kernel, patching is required.
+   But we still can look at server side:
+   
+<tscreen><verb>
+   ss -x src "/tmp/.X11-unix/*"
+</verb></tscreen>
+
+</itemize>
+
+
+<sect> Returning to ground: real manual  
+
+<p>
+<sect1> Command arguments
+
+<p> General format of arguments to <tt/ss/ is:
+
+<tscreen><verb>
+       ss [ OPTIONS ] [ STATE-FILTER ] [ ADDRESS-FILTER ]
+</verb></tscreen>
+
+<sect2><tt/OPTIONS/
+<p> <tt/OPTIONS/ is list of single letter options, using common unix
+conventions.
+
+<itemize>
+<item><tt/-h/  - show help page
+<item><tt/-?/  - the same, of course
+<item><tt/-v/, <tt/-V/  - print version of <tt/ss/ and exit
+<item><tt/-s/  - print summary statistics. This option does not parse
+socket lists obtaining summary from various sources. It is useful
+when amount of sockets is so huge that parsing <tt>/proc/net/tcp</tt>
+is painful.
+<item><tt/-D FILE/  - do not display anything, just dump raw information
+about TCP sockets to <tt/FILE/ after applying filters. If <tt/FILE/ is <tt/-/
+<tt/stdout/ is used. 
+<item><tt/-F FILE/  - read continuation of filter from <tt/FILE/.
+Each line of <tt/FILE/ is interpreted like single command line option.
+If <tt/FILE/ is <tt/-/ <tt/stdin/ is used. 
+<item><tt/-r/  - try to resolve numeric address/ports
+<item><tt/-n/  - do not try to resolve ports
+<item><tt/-o/  - show some optional information, f.e. TCP timers
+<item><tt/-i/  - show some infomration specific to TCP (RTO, congestion
+window, slow start threshould etc.)
+<item><tt/-e/  - show even more optional information
+<item><tt/-m/  - show extended information on memory used by the socket.
+It is available only with <tt/tcp_diag/ enabled.
+<item><tt/-p/  - show list of processes owning the socket
+<item><tt/-f FAMILY/ - default address family used for parsing addresses.
+                 Also this option limits listing to sockets supporting
+                 given address family. Currently the following families
+                 are supported: <tt/unix/, <tt/inet/, <tt/inet6/, <tt/link/,
+                 <tt/netlink/.
+<item><tt/-4/ - alias for <tt/-f inet/
+<item><tt/-6/ - alias for <tt/-f inet6/
+<item><tt/-0/ - alias for <tt/-f link/
+<item><tt/-A LIST-OF-TABLES/ - list of socket tables to dump, separated
+                 by commas. The following identifiers are understood:
+                 <tt/all/, <tt/inet/, <tt/tcp/, <tt/udp/, <tt/raw/,
+                 <tt/unix/, <tt/packet/, <tt/netlink/, <tt/unix_dgram/,
+                 <tt/unix_stream/, <tt/packet_raw/, <tt/packet_dgram/.
+<item><tt/-x/ - alias for <tt/-A unix/
+<item><tt/-t/ - alias for <tt/-A tcp/
+<item><tt/-u/ - alias for <tt/-A udp/
+<item><tt/-w/ - alias for <tt/-A raw/
+<item><tt/-a/ - show sockets of all the states. By default sockets
+                in states <tt/LISTEN/, <tt/TIME-WAIT/, <tt/SYN_RECV/
+                and <tt/CLOSE/ are skipped.
+<item><tt/-l/ - show only sockets in state <tt/LISTEN/ 
+</itemize>
+
+<sect2><tt/STATE-FILTER/
+
+<p><tt/STATE-FILTER/ allows to construct arbitrary set of
+states to match. Its syntax is sequence of keywords <tt/state/
+and <tt/exclude/ followed by identifier of state.
+Available identifiers are:
+
+<p>
+<itemize>
+<item> All standard TCP states: <tt/established/, <tt/syn-sent/,
+<tt/syn-recv/, <tt/fin-wait-1/, <tt/fin-wait-2/, <tt/time-wait/,
+<tt/closed/, <tt/close-wait/, <tt/last-ack/, <tt/listen/ and <tt/closing/.
+
+<item><tt/all/ - for all the states 
+<item><tt/connected/ - all the states except for <tt/listen/ and <tt/closed/ 
+<item><tt/synchronized/ - all the <tt/connected/ states except for 
+<tt/syn-sent/
+<item><tt/bucket/ - states, which are maintained as minisockets, i.e.
+<tt/time-wait/ and <tt/syn-recv/.
+<item><tt/big/ - opposite to <tt/bucket/
+</itemize>
+
+<sect2><tt/ADDRESS_FILTER/
+
+<p><tt/ADDRESS_FILTER/ is boolean expression with operations <tt/and/, <tt/or/
+and <tt/not/, which can be abbreviated in C style f.e. as <tt/&amp/,
+<tt/&amp&amp/.
+
+<p>
+Predicates check socket addresses, both local and remote.
+There are the following kinds of predicates:
+
+<itemize>
+<item> <tt/dst ADDRESS_PATTERN/ - matches remote address and port
+<item> <tt/src ADDRESS_PATTERN/ - matches local address and port
+<item> <tt/dport RELOP PORT/    - compares remote port to a number
+<item> <tt/sport RELOP PORT/    - compares local port to a number
+<item> <tt/autobound/           - checks that socket is bound to an ephemeral
+                                  port
+</itemize>
+
+<p><tt/RELOP/ is some of <tt/&lt=/, <tt/&gt=/, <tt/==/ etc.
+To make this more convinient for use in unix shell, alphabetic
+FORTRAN-like notations <tt/le/, <tt/gt/ etc. are accepted as well.
+
+<p>The format and semantics of <tt/ADDRESS_PATTERN/ depends on address
+family.
+
+<itemize>
+<item><tt/inet/ - <tt/ADDRESS_PATTERN/ consists of IP prefix, optionally
+followed by colon and port. If prefix or port part is absent or replaced
+with <tt/*/, this means wildcard match.
+<item><tt/inet6/ - The same as <tt/inet/, only prefix refers to an IPv6
+address. Unlike <tt/inet/ colon becomes ambiguous, so that <tt/ss/ allows
+to use scheme, like used in URLs, where address is suppounded with
+<tt/[/ ... <tt/]/.
+<item><tt/unix/ - <tt/ADDRESS_PATTERN/ is shell-style wildcard.
+<item><tt/packet/ - format looks like <tt/inet/, only interface index
+stays instead of port and link layer protocol id instead of address.
+<item><tt/netlink/ - format looks like <tt/inet/, only socket pid
+stays instead of port and netlink channel instead of address.
+</itemize>
+
+<p><tt/PORT/ is syntactically <tt/ADDRESS_PATTERN/ with wildcard
+address part. Certainly, it is undefined for UNIX sockets. 
+
+<sect1> Environment variables
+
+<p>
+<tt/ss/ allows to change source of information using various
+environment variables:
+
+<p>
+<itemize>
+<item> <tt/PROC_SLABINFO/  to override <tt>/proc/slabinfo</tt>
+<item> <tt/PROC_NET_TCP/  to override <tt>/proc/net/tcp</tt>
+<item> <tt/PROC_NET_UDP/  to override <tt>/proc/net/udp</tt>
+<item> etc.
+</itemize> 
+
+<p>
+Variable <tt/PROC_ROOT/ allows to change root of all the <tt>/proc/</tt>
+hierarchy.
+
+<p>
+Variable <tt/TCPDIAG_FILE/ prescribes to open a file instead of
+requesting kernel to dump information about TCP sockets.
+
+
+<p> This option is used mainly to investigate bug reports,
+when dumps of files usually found in <tt>/proc/</tt> are recevied
+by e-mail.
+
+<sect1> Output format
+
+<p>Six columns. The first is <tt/Netid/, it denotes socket type and
+transport protocol, when it is ambiguous: <tt/tcp/, <tt/udp/, <tt/raw/,
+<tt/u_str/ is abbreviation for <tt/unix_stream/, <tt/u_dgr/ for UNIX
+datagram sockets, <tt/nl/ for netlink, <tt/p_raw/ and <tt/p_dgr/ for
+raw and datagram packet sockets. This column is optional, it will
+be hidden, if filter selects an unique netid.
+
+<p>
+The second column is <tt/State/. Socket state is displayed here.
+The names are standard TCP names, except for <tt/UNCONN/, which
+cannot happen for TCP, but normal for not connected sockets
+of another types. Again, this column can be hidden.
+
+<p>
+Then two columns (<tt/Recv-Q/ and <tt/Send-Q/) showing amount of data
+queued for receive and transmit.
+
+<p>
+And the last two columns display local address and port of the socket
+and its peer address, if the socket is connected.
+
+<p>
+If options <tt/-o/, <tt/-e/ or <tt/-p/ were given, options are
+displayed not in fixed positions but separated by spaces pairs:
+<tt/option:value/. If value is not a single number, it is presented
+as list of values, enclosed to <tt/(/ ... <tt/)/ and separated with
+commas. F.e.
+
+<tscreen><verb>
+   timer:(keepalive,111min,0)
+</verb></tscreen>
+is typical format for TCP timer (option <tt/-o/).
+
+<tscreen><verb>
+   users:((X,113,3))
+</verb></tscreen>
+is typical for list of users (option <tt/-p/).
+
+
+<sect>Some numbers
+
+<p>
+Well, let us use <tt/pidentd/ and a tool <tt/ibench/ to measure
+its performance. It is 30 requests per second here. Nothing to test,
+it is too slow. OK, let us patch pidentd with patch from directory
+Patches. After this it handles about 4300 requests per second
+and becomes handy tool to pollute socket tables with lots of timewait
+buckets.
+
+<p>
+So, each test starts from pollution tables with 30000 sockets
+and then doing full dump of the table piped to wc and measuring
+timings with time:
+
+<p>Results:
+
+<itemize>
+<item> <tt/netstat -at/ - 15.6 seconds
+<item> <tt/ss -atr/, but without <tt/tcp_diag/     - 5.4 seconds
+<item> <tt/ss -atr/ with <tt/tcp_diag/     - 0.47 seconds
+</itemize>
+
+No comments. Though one comment is necessary, most of time
+without <tt/tcp_diag/ is wasted inside kernel with completely
+blocked networking. More than 10 seconds, yes. <tt/tcp_diag/
+does the same work for 100 milliseconds of system time.
+
+</article>
diff --git a/iproute2/etc/iproute2/bpf_pinning b/iproute2/etc/iproute2/bpf_pinning
new file mode 100644
index 0000000..2b39c70
--- /dev/null
+++ b/iproute2/etc/iproute2/bpf_pinning
@@ -0,0 +1,6 @@
+#
+# subpath mappings from mount point for pinning
+#
+#3	tracing
+#4	foo/bar
+#5	tc/cls1
diff --git a/iproute2/etc/iproute2/ematch_map b/iproute2/etc/iproute2/ematch_map
new file mode 100644
index 0000000..1823983
--- /dev/null
+++ b/iproute2/etc/iproute2/ematch_map
@@ -0,0 +1,7 @@
+# lookup table for ematch kinds
+1	cmp
+2	nbyte
+3	u32
+4	meta
+7	canid
+8	ipset
diff --git a/iproute2/etc/iproute2/group b/iproute2/etc/iproute2/group
new file mode 100644
index 0000000..6f000b2
--- /dev/null
+++ b/iproute2/etc/iproute2/group
@@ -0,0 +1,2 @@
+# device group names
+0	default
diff --git a/iproute2/etc/iproute2/nl_protos b/iproute2/etc/iproute2/nl_protos
new file mode 100644
index 0000000..43418f3
--- /dev/null
+++ b/iproute2/etc/iproute2/nl_protos
@@ -0,0 +1,23 @@
+# Netlink protocol names mapping
+
+0   rtnl
+1   unused
+2   usersock
+3   fw
+4   tcpdiag
+5   nflog
+6   xfrm
+7   selinux
+8   iscsi
+9   audit
+10  fiblookup
+11  connector
+12  nft 
+13  ip6fw
+14  dec-rt
+15  uevent
+16  genl
+18  scsi-trans
+19  ecryptfs
+20  rdma
+21  crypto 
diff --git a/iproute2/etc/iproute2/rt_dsfield b/iproute2/etc/iproute2/rt_dsfield
new file mode 100644
index 0000000..1426d60
--- /dev/null
+++ b/iproute2/etc/iproute2/rt_dsfield
@@ -0,0 +1,26 @@
+# Differentiated field values
+# These include the DSCP and unused bits
+0x0	default
+# Newer RFC2597 values
+0x28	AF11
+0x30	AF12
+0x38	AF13
+0x48	AF21
+0x50	AF22
+0x58	AF23
+0x68	AF31
+0x70	AF32
+0x78	AF33
+0x88	AF41
+0x90	AF42
+0x98	AF43
+# Older values RFC2474
+0x20	CS1
+0x40	CS2
+0x60	CS3
+0x80	CS4
+0xA0	CS5
+0xC0	CS6
+0xE0	CS7
+# RFC 2598
+0xB8	EF
diff --git a/iproute2/etc/iproute2/rt_protos b/iproute2/etc/iproute2/rt_protos
new file mode 100644
index 0000000..82cf9c4
--- /dev/null
+++ b/iproute2/etc/iproute2/rt_protos
@@ -0,0 +1,31 @@
+#
+# Reserved protocols.
+#
+0	unspec
+1	redirect
+2	kernel
+3	boot
+4	static
+8	gated
+9	ra
+10	mrt
+11	zebra
+12	bird
+13	dnrouted
+14	xorp
+15	ntk
+16      dhcp
+42	babel
+
+#
+#	Used by me for gated
+#
+254	gated/aggr
+253	gated/bgp
+252	gated/ospf
+251	gated/ospfase
+250	gated/rip
+249	gated/static
+248	gated/conn
+247	gated/inet
+246	gated/default
diff --git a/iproute2/etc/iproute2/rt_realms b/iproute2/etc/iproute2/rt_realms
new file mode 100644
index 0000000..eedd76d
--- /dev/null
+++ b/iproute2/etc/iproute2/rt_realms
@@ -0,0 +1,13 @@
+#
+# reserved values
+#
+0	cosmos
+#
+# local
+#
+#1	inr.ac
+#2	inr.ruhep
+#3	freenet
+#4	radio-msu
+#5	russia
+#6	internet
diff --git a/iproute2/etc/iproute2/rt_scopes b/iproute2/etc/iproute2/rt_scopes
new file mode 100644
index 0000000..8514bc1
--- /dev/null
+++ b/iproute2/etc/iproute2/rt_scopes
@@ -0,0 +1,11 @@
+#
+# reserved values
+#
+0	global
+255	nowhere
+254	host
+253	link
+#
+# pseudo-reserved
+#
+200	site
diff --git a/iproute2/etc/iproute2/rt_tables b/iproute2/etc/iproute2/rt_tables
new file mode 100644
index 0000000..541abfd
--- /dev/null
+++ b/iproute2/etc/iproute2/rt_tables
@@ -0,0 +1,11 @@
+#
+# reserved values
+#
+255	local
+254	main
+253	default
+0	unspec
+#
+# local
+#
+#1	inr.ruhep
diff --git a/iproute2/etc/iproute2/rt_tables.d/README b/iproute2/etc/iproute2/rt_tables.d/README
new file mode 100644
index 0000000..79386f8
--- /dev/null
+++ b/iproute2/etc/iproute2/rt_tables.d/README
@@ -0,0 +1,3 @@
+Each file in this directory is an rt_tables configuration file. iproute2
+commands scan this directory processing all files that end in '.conf'.
+
diff --git a/iproute2/examples/README.cbq b/iproute2/examples/README.cbq
new file mode 100644
index 0000000..38c1089
--- /dev/null
+++ b/iproute2/examples/README.cbq
@@ -0,0 +1,122 @@
+# CHANGES
+# -------
+# v0.3a2- fixed bug in "if" operator. Thanks kad@dgtu.donetsk.ua.
+# v0.3a-  added TIME parameter. Example:
+#         TIME=00:00-19:00;64Kbit/6Kbit
+#         So, between 00:00 and 19:00 RATE will be 64Kbit.
+#         Just start "cbq.init timecheck" periodically from cron (every 10
+#         minutes for example).
+#         !!! Anyway you MUST start "cbq.init start" for CBQ initialize.
+# v0.2 -  Some cosmetique changes. Now it more compatible with
+#         old bash version. Thanks to Stanislav V. Voronyi
+#         <stas@cnti.uanet.kharkov.ua>.
+# v0.1 -  First public release
+# 
+# README
+# ------
+# 
+# First of all - this is just a SIMPLE EXAMPLE of CBQ power.
+# Don't ask me "why" and "how" :)
+# 
+# This is an example of using CBQ (Class Based Queueing) and policy-based
+# filter for building smart ethernet shapers. All CBQ parameters are
+# correct only for ETHERNET (eth0,1,2..) linux interfaces. It works for
+# ARCNET too (just set bandwidth parameter to 2Mbit). It was tested
+# on 2.1.125-2.1.129 linux kernels (KSI linux, Nostromo version) and 
+# ip-route utility by A.Kuznetsov (iproute2-ss981101 version). 
+# You can download ip-route from ftp://ftp.inr.ac.ru/ip-routing or
+# get iproute2*.rpm (compiled with glibc) from ftp.ksi-linux.com.
+# 
+# 
+# HOW IT WORKS
+# 
+# Each shaper must be described by config file in $CBQ_PATH
+# (/etc/sysconfig/cbq/) directory - one config file for each CBQ shaper.
+# 
+# Some words about config file name:
+# Each shaper has its personal ID - two byte HEX number. Really ID is 
+# CBQ class.
+# So, filename looks like:
+# 
+# cbq-1280.My_first_shaper
+# ^^^ ^^^  ^^^^^^^^^^^^^
+#  |  |            |______ Shaper name - any word
+#  |  |___________________ ID (0000-FFFF), let ID looks like shaper's rate
+#  |______________________ Filename must begin from "cbq-" 
+# 
+# 
+# Config file describes shaper parameters and source[destination] 
+# address[port].
+# For example let's prepare /etc/sysconfig/cbq/cbq-1280.My_first_shaper:
+# 
+# ----------8<---------------------
+# DEVICE=eth0,10Mbit,1Mbit
+# RATE=128Kbit
+# WEIGHT=10Kbit
+# PRIO=5
+# RULE=192.168.1.0/24
+# ----------8<---------------------
+# 
+# This is minimal configuration, where:
+# DEVICE:  eth0   - device where we do control our traffic
+#          10Mbit - REAL ethernet card bandwidth
+#          1Mbit  - "weight" of :1 class (parent for all shapers for eth0),
+#                   as a rule of thumb weight=batdwidth/10.
+#          100Mbit adapter's example: DEVICE=eth0,100Mbit,10Mbit
+#          *** If you want to build more than one shaper per device it's
+#              enough to describe bandwidth and weight once  - cbq.init
+#              is smart :) You can put only 'DEVICE=eth0' into cbq-* 
+#              config file for eth0.
+# 
+# RATE:    Shaper's speed - Kbit,Mbit or bps (bytes per second)
+# 
+# WEIGHT:  "weight" of shaper (CBQ class). Like for DEVICE - approx. RATE/10
+# 
+# PRIO:    shaper's priority from 1 to 8 where 1 is the highest one.
+#          I do always use "5" for all my shapers.
+# 
+# RULE:    [source addr][:source port],[dest addr][:dest port]
+#          Some examples:
+# RULE=10.1.1.0/24:80         - all traffic for network 10.1.1.0 to port 80
+#                               will be shaped.
+# RULE=10.2.2.5               - shaper works only for IP address 10.2.2.5   
+# RULE=:25,10.2.2.128/25:5000 - all traffic from any address and port 25 to
+#                               address 10.2.2.128 - 10.2.2.255 and port 5000
+#                               will be shaped.
+# RULE=10.5.5.5:80,           - shaper active only for traffic from port 80 of
+#                               address 10.5.5.5
+# Multiple RULE fields per one config file are allowed. For example:
+# RULE=10.1.1.2:80
+# RULE=10.1.1.2:25
+# RULE=10.1.1.2:110
+# 
+# *** ATTENTION!!!
+# All shapers do work only for outgoing traffic!
+# So, if you want to build bidirectional shaper you must set it up for
+# both ethernet card. For example let's build shaper for our linux box like:
+# 
+#                     ---------             192.168.1.1
+# BACKBONE -----eth0-|  linux  |-eth1------*[our client]
+#                     ---------
+# 
+# Let all traffic from backbone to client will be shaped at 28Kbit and
+# traffic from client to backbone - at 128Kbit. We need two config files:
+# 
+# ---8<-----/etc/sysconfig/cbq/cbq-28.client-out----
+# DEVICE=eth1,10Mbit,1Mbit
+# RATE=28Kbit
+# WEIGHT=2Kbit
+# PRIO=5
+# RULE=192.168.1.1
+# ---8<---------------------------------------------
+# 
+# ---8<-----/etc/sysconfig/cbq/cbq-128.client-in----
+# DEVICE=eth0,10Mbit,1Mbit
+# RATE=128Kbit
+# WEIGHT=10Kbit
+# PRIO=5
+# RULE=192.168.1.1,
+# ---8<---------------------------------------------
+#                 ^pay attention to "," - this is source address!
+# 
+# Enjoy.
diff --git a/iproute2/examples/SYN-DoS.rate.limit b/iproute2/examples/SYN-DoS.rate.limit
new file mode 100644
index 0000000..8766b67
--- /dev/null
+++ b/iproute2/examples/SYN-DoS.rate.limit
@@ -0,0 +1,49 @@
+#! /bin/sh -x
+#
+# sample script on using the ingress capabilities
+# this script shows how one can rate limit incoming SYNs
+# Useful for TCP-SYN attack protection. You can use
+# IPchains to have more powerful additions to the SYN (eg 
+# in addition the subnet)
+#
+#path to various utilities;
+#change to reflect yours.
+#
+IPROUTE=/root/DS-6-beta/iproute2-990530-dsing
+TC=$IPROUTE/tc/tc
+IP=$IPROUTE/ip/ip
+IPCHAINS=/root/DS-6-beta/ipchains-1.3.9/ipchains
+INDEV=eth2
+#
+# tag all incoming SYN packets through $INDEV as mark value 1
+############################################################ 
+$IPCHAINS -A input -i $INDEV -y -m 1
+############################################################ 
+#
+# install the ingress qdisc on the ingress interface
+############################################################ 
+$TC qdisc add dev $INDEV handle ffff: ingress
+############################################################ 
+
+#
+# 
+# SYN packets are 40 bytes (320 bits) so three SYNs equals
+# 960 bits (approximately 1kbit); so we rate limit below
+# the incoming SYNs to 3/sec (not very sueful really; but
+#serves to show the point - JHS
+############################################################ 
+$TC filter add dev $INDEV parent ffff: protocol ip prio 50 handle 1 fw \
+police rate 1kbit burst 40 mtu 9k drop flowid :1
+############################################################ 
+
+
+#
+echo "---- qdisc parameters Ingress  ----------"
+$TC qdisc ls dev $INDEV
+echo "---- Class parameters Ingress  ----------"
+$TC class ls dev $INDEV
+echo "---- filter parameters Ingress ----------"
+$TC filter ls dev $INDEV parent ffff:
+
+#deleting the ingress qdisc
+#$TC qdisc del $INDEV ingress
diff --git a/iproute2/examples/bpf/README b/iproute2/examples/bpf/README
new file mode 100644
index 0000000..4247257
--- /dev/null
+++ b/iproute2/examples/bpf/README
@@ -0,0 +1,13 @@
+eBPF toy code examples (running in kernel) to familiarize yourself
+with syntax and features:
+
+ - bpf_prog.c		-> Classifier examples with using maps
+ - bpf_shared.c		-> Ingress/egress map sharing example
+ - bpf_tailcall.c	-> Using tail call chains
+ - bpf_cyclic.c		-> Simple cycle as tail calls
+ - bpf_graft.c		-> Demo on altering runtime behaviour
+
+User space code example:
+
+ - bpf_agent.c		-> Counterpart to bpf_prog.c for user
+                           space to transfer/read out map data
diff --git a/iproute2/examples/bpf/bpf_agent.c b/iproute2/examples/bpf/bpf_agent.c
new file mode 100644
index 0000000..f9b9ce3
--- /dev/null
+++ b/iproute2/examples/bpf/bpf_agent.c
@@ -0,0 +1,258 @@
+/*
+ * eBPF user space agent part
+ *
+ * Simple, _self-contained_ user space agent for the eBPF kernel
+ * ebpf_prog.c program, which gets all map fds passed from tc via unix
+ * domain socket in one transaction and can thus keep referencing
+ * them from user space in order to read out (or possibly modify)
+ * map data. Here, just as a minimal example to display counters.
+ *
+ * The agent only uses the bpf(2) syscall API to read or possibly
+ * write to eBPF maps, it doesn't need to be aware of the low-level
+ * bytecode parts and/or ELF parsing bits.
+ *
+ * ! For more details, see header comment in bpf_prog.c !
+ *
+ * gcc bpf_agent.c -o bpf_agent -Wall -O2
+ *
+ * For example, a more complex user space agent could run on each
+ * host, reading and writing into eBPF maps used by tc classifier
+ * and actions. It would thus allow for implementing a distributed
+ * tc architecture, for example, which would push down central
+ * policies into eBPF maps, and thus altering run-time behaviour.
+ *
+ *   -- Happy eBPF hacking! ;)
+ */
+
+#define _GNU_SOURCE
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <unistd.h>
+#include <stdint.h>
+#include <assert.h>
+
+#include <sys/un.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/socket.h>
+
+/* Just some misc macros as min(), offsetof(), etc. */
+#include "../../include/utils.h"
+/* Common code from fd passing. */
+#include "../../include/bpf_scm.h"
+/* Common, shared definitions with ebpf_prog.c */
+#include "bpf_shared.h"
+/* Mini syscall wrapper */
+#include "bpf_sys.h"
+
+static void bpf_dump_drops(int fd)
+{
+	int cpu, max;
+
+	max = sysconf(_SC_NPROCESSORS_ONLN);
+
+	printf(" `- number of drops:");
+	for (cpu = 0; cpu < max; cpu++) {
+		long drops;
+
+		assert(bpf_lookup_elem(fd, &cpu, &drops) == 0);
+		printf("\tcpu%d: %5ld", cpu, drops);
+	}
+	printf("\n");
+}
+
+static void bpf_dump_queue(int fd)
+{
+	/* Just for the same of the example. */
+	int max_queue = 4, i;
+
+	printf("  | nic queues:");
+	for (i = 0; i < max_queue; i++) {
+		struct count_queue cq;
+		int ret;
+
+		memset(&cq, 0, sizeof(cq));
+		ret = bpf_lookup_elem(fd, &i, &cq);
+		assert(ret == 0 || (ret < 0 && errno == ENOENT));
+
+		printf("\tq%d:[pkts: %ld, mis: %ld]",
+		       i, cq.total, cq.mismatch);
+	}
+	printf("\n");
+}
+
+static void bpf_dump_proto(int fd)
+{
+	uint8_t protos[] = { IPPROTO_TCP, IPPROTO_UDP, IPPROTO_ICMP };
+	char *names[] = { "tcp", "udp", "icmp" };
+	int i;
+
+	printf("  ` protos:");
+	for (i = 0; i < ARRAY_SIZE(protos); i++) {
+		struct count_tuple ct;
+		int ret;
+
+		memset(&ct, 0, sizeof(ct));
+		ret = bpf_lookup_elem(fd, &protos[i], &ct);
+		assert(ret == 0 || (ret < 0 && errno == ENOENT));
+
+		printf("\t%s:[pkts: %ld, bytes: %ld]",
+		       names[i], ct.packets, ct.bytes);
+	}
+	printf("\n");
+}
+
+static void bpf_dump_map_data(int *tfd)
+{
+	int i;
+
+	for (i = 0; i < 30; i++) {
+		const int period = 5;
+
+		printf("data, period: %dsec\n", period);
+
+		bpf_dump_drops(tfd[BPF_MAP_ID_DROPS]);
+		bpf_dump_queue(tfd[BPF_MAP_ID_QUEUE]);
+		bpf_dump_proto(tfd[BPF_MAP_ID_PROTO]);
+
+		sleep(period);
+	}
+}
+
+static void bpf_info_loop(int *fds, struct bpf_map_aux *aux)
+{
+	int i, tfd[BPF_MAP_ID_MAX];
+
+	printf("ver: %d\nobj: %s\ndev: %lu\nino: %lu\nmaps: %u\n",
+	       aux->uds_ver, aux->obj_name, aux->obj_st.st_dev,
+	       aux->obj_st.st_ino, aux->num_ent);
+
+	for (i = 0; i < aux->num_ent; i++) {
+		printf("map%d:\n", i);
+		printf(" `- fd: %u\n", fds[i]);
+		printf("  | serial: %u\n", aux->ent[i].id);
+		printf("  | type: %u\n", aux->ent[i].type);
+		printf("  | max elem: %u\n", aux->ent[i].max_elem);
+		printf("  | size key: %u\n", aux->ent[i].size_key);
+		printf("  ` size val: %u\n", aux->ent[i].size_value);
+
+		tfd[aux->ent[i].id] = fds[i];
+	}
+
+	bpf_dump_map_data(tfd);
+}
+
+static void bpf_map_get_from_env(int *tfd)
+{
+	char key[64], *val;
+	int i;
+
+	for (i = 0; i < BPF_MAP_ID_MAX; i++) {
+		memset(key, 0, sizeof(key));
+		snprintf(key, sizeof(key), "BPF_MAP%d", i);
+
+		val = getenv(key);
+		assert(val != NULL);
+
+		tfd[i] = atoi(val);
+	}
+}
+
+static int bpf_map_set_recv(int fd, int *fds,  struct bpf_map_aux *aux,
+			    unsigned int entries)
+{
+	struct bpf_map_set_msg msg;
+	int *cmsg_buf, min_fd, i;
+	char *amsg_buf, *mmsg_buf;
+
+	cmsg_buf = bpf_map_set_init(&msg, NULL, 0);
+	amsg_buf = (char *)msg.aux.ent;
+	mmsg_buf = (char *)&msg.aux;
+
+	for (i = 0; i < entries; i += min_fd) {
+		struct cmsghdr *cmsg;
+		int ret;
+
+		min_fd = min(BPF_SCM_MAX_FDS * 1U, entries - i);
+
+		bpf_map_set_init_single(&msg, min_fd);
+
+		ret = recvmsg(fd, &msg.hdr, 0);
+		if (ret <= 0)
+			return ret ? : -1;
+
+		cmsg = CMSG_FIRSTHDR(&msg.hdr);
+		if (!cmsg || cmsg->cmsg_type != SCM_RIGHTS)
+			return -EINVAL;
+		if (msg.hdr.msg_flags & MSG_CTRUNC)
+			return -EIO;
+
+		min_fd = (cmsg->cmsg_len - sizeof(*cmsg)) / sizeof(fd);
+		if (min_fd > entries || min_fd <= 0)
+			return -1;
+
+		memcpy(&fds[i], cmsg_buf, sizeof(fds[0]) * min_fd);
+		memcpy(&aux->ent[i], amsg_buf, sizeof(aux->ent[0]) * min_fd);
+		memcpy(aux, mmsg_buf, offsetof(struct bpf_map_aux, ent));
+
+		if (i + min_fd == aux->num_ent)
+			break;
+	}
+
+	return 0;
+}
+
+int main(int argc, char **argv)
+{
+	int fds[BPF_SCM_MAX_FDS];
+	struct bpf_map_aux aux;
+	struct sockaddr_un addr;
+	int fd, ret, i;
+
+	/* When arguments are being passed, we take it as a path
+	 * to a Unix domain socket, otherwise we grab the fds
+	 * from the environment to demonstrate both possibilities.
+	 */
+	if (argc == 1) {
+		int tfd[BPF_MAP_ID_MAX];
+
+		bpf_map_get_from_env(tfd);
+		bpf_dump_map_data(tfd);
+
+		return 0;
+	}
+
+	fd = socket(AF_UNIX, SOCK_DGRAM, 0);
+	if (fd < 0) {
+		fprintf(stderr, "Cannot open socket: %s\n",
+			strerror(errno));
+		exit(1);
+	}
+
+	memset(&addr, 0, sizeof(addr));
+	addr.sun_family = AF_UNIX;
+	strncpy(addr.sun_path, argv[argc - 1], sizeof(addr.sun_path));
+
+	ret = bind(fd, (struct sockaddr *)&addr, sizeof(addr));
+	if (ret < 0) {
+		fprintf(stderr, "Cannot bind to socket: %s\n",
+			strerror(errno));
+		exit(1);
+	}
+
+	memset(fds, 0, sizeof(fds));
+	memset(&aux, 0, sizeof(aux));
+
+	ret = bpf_map_set_recv(fd, fds, &aux, BPF_SCM_MAX_FDS);
+	if (ret >= 0)
+		bpf_info_loop(fds, &aux);
+
+	for (i = 0; i < aux.num_ent; i++)
+		close(fds[i]);
+
+	close(fd);
+	return 0;
+}
diff --git a/iproute2/examples/bpf/bpf_cyclic.c b/iproute2/examples/bpf/bpf_cyclic.c
new file mode 100644
index 0000000..c66cbec
--- /dev/null
+++ b/iproute2/examples/bpf/bpf_cyclic.c
@@ -0,0 +1,30 @@
+#include "../../include/bpf_api.h"
+
+/* Cyclic dependency example to test the kernel's runtime upper
+ * bound on loops. Also demonstrates on how to use direct-actions,
+ * loaded as: tc filter add [...] bpf da obj [...]
+ */
+#define JMP_MAP_ID	0xabccba
+
+BPF_PROG_ARRAY(jmp_tc, JMP_MAP_ID, PIN_OBJECT_NS, 1);
+
+__section_tail(JMP_MAP_ID, 0)
+int cls_loop(struct __sk_buff *skb)
+{
+	char fmt[] = "cb: %u\n";
+
+	trace_printk(fmt, sizeof(fmt), skb->cb[0]++);
+	tail_call(skb, &jmp_tc, 0);
+
+	skb->tc_classid = TC_H_MAKE(1, 42);
+	return TC_ACT_OK;
+}
+
+__section_cls_entry
+int cls_entry(struct __sk_buff *skb)
+{
+	tail_call(skb, &jmp_tc, 0);
+	return TC_ACT_SHOT;
+}
+
+BPF_LICENSE("GPL");
diff --git a/iproute2/examples/bpf/bpf_graft.c b/iproute2/examples/bpf/bpf_graft.c
new file mode 100644
index 0000000..f48fd02
--- /dev/null
+++ b/iproute2/examples/bpf/bpf_graft.c
@@ -0,0 +1,67 @@
+#include "../../include/bpf_api.h"
+
+/* This example demonstrates how classifier run-time behaviour
+ * can be altered with tail calls. We start out with an empty
+ * jmp_tc array, then add section aaa to the array slot 0, and
+ * later on atomically replace it with section bbb. Note that
+ * as shown in other examples, the tc loader can prepopulate
+ * tail called sections, here we start out with an empty one
+ * on purpose to show it can also be done this way.
+ *
+ * tc filter add dev foo parent ffff: bpf obj graft.o
+ * tc exec bpf dbg
+ *   [...]
+ *   Socket Thread-20229 [001] ..s. 138993.003923: : fallthrough
+ *   <idle>-0            [001] ..s. 138993.202265: : fallthrough
+ *   Socket Thread-20229 [001] ..s. 138994.004149: : fallthrough
+ *   [...]
+ *
+ * tc exec bpf graft m:globals/jmp_tc key 0 obj graft.o sec aaa
+ * tc exec bpf dbg
+ *   [...]
+ *   Socket Thread-19818 [002] ..s. 139012.053587: : aaa
+ *   <idle>-0            [002] ..s. 139012.172359: : aaa
+ *   Socket Thread-19818 [001] ..s. 139012.173556: : aaa
+ *   [...]
+ *
+ * tc exec bpf graft m:globals/jmp_tc key 0 obj graft.o sec bbb
+ * tc exec bpf dbg
+ *   [...]
+ *   Socket Thread-19818 [002] ..s. 139022.102967: : bbb
+ *   <idle>-0            [002] ..s. 139022.155640: : bbb
+ *   Socket Thread-19818 [001] ..s. 139022.156730: : bbb
+ *   [...]
+ */
+
+BPF_PROG_ARRAY(jmp_tc, 0, PIN_GLOBAL_NS, 1);
+
+__section("aaa")
+int cls_aaa(struct __sk_buff *skb)
+{
+	char fmt[] = "aaa\n";
+
+	trace_printk(fmt, sizeof(fmt));
+	return TC_H_MAKE(1, 42);
+}
+
+__section("bbb")
+int cls_bbb(struct __sk_buff *skb)
+{
+	char fmt[] = "bbb\n";
+
+	trace_printk(fmt, sizeof(fmt));
+	return TC_H_MAKE(1, 43);
+}
+
+__section_cls_entry
+int cls_entry(struct __sk_buff *skb)
+{
+	char fmt[] = "fallthrough\n";
+
+	tail_call(skb, &jmp_tc, 0);
+	trace_printk(fmt, sizeof(fmt));
+
+	return BPF_H_DEFAULT;
+}
+
+BPF_LICENSE("GPL");
diff --git a/iproute2/examples/bpf/bpf_prog.c b/iproute2/examples/bpf/bpf_prog.c
new file mode 100644
index 0000000..4728049
--- /dev/null
+++ b/iproute2/examples/bpf/bpf_prog.c
@@ -0,0 +1,499 @@
+/*
+ * eBPF kernel space program part
+ *
+ * Toy eBPF program for demonstration purposes, some parts derived from
+ * kernel tree's samples/bpf/sockex2_kern.c example.
+ *
+ * More background on eBPF, kernel tree: Documentation/networking/filter.txt
+ *
+ * Note, this file is rather large, and most classifier and actions are
+ * likely smaller to accomplish one specific use-case and are tailored
+ * for high performance. For performance reasons, you might also have the
+ * classifier and action already merged inside the classifier.
+ *
+ * In order to show various features it serves as a bigger programming
+ * example, which you should feel free to rip apart and experiment with.
+ *
+ * Compilation, configuration example:
+ *
+ *  Note: as long as the BPF backend in LLVM is still experimental,
+ *  you need to build LLVM with LLVM with --enable-experimental-targets=BPF
+ *  Also, make sure your 4.1+ kernel is compiled with CONFIG_BPF_SYSCALL=y,
+ *  and you have libelf.h and gelf.h headers and can link tc against -lelf.
+ *
+ *  In case you need to sync kernel headers, go to your kernel source tree:
+ *  # make headers_install INSTALL_HDR_PATH=/usr/
+ *
+ *  $ export PATH=/home/<...>/llvm/Debug+Asserts/bin/:$PATH
+ *  $ clang -O2 -emit-llvm -c bpf_prog.c -o - | llc -march=bpf -filetype=obj -o bpf.o
+ *  $ objdump -h bpf.o
+ *  [...]
+ *  3 classifier    000007f8  0000000000000000  0000000000000000  00000040  2**3
+ *                  CONTENTS, ALLOC, LOAD, RELOC, READONLY, CODE
+ *  4 action-mark   00000088  0000000000000000  0000000000000000  00000838  2**3
+ *                  CONTENTS, ALLOC, LOAD, RELOC, READONLY, CODE
+ *  5 action-rand   00000098  0000000000000000  0000000000000000  000008c0  2**3
+ *                  CONTENTS, ALLOC, LOAD, RELOC, READONLY, CODE
+ *  6 maps          00000030  0000000000000000  0000000000000000  00000958  2**2
+ *                  CONTENTS, ALLOC, LOAD, DATA
+ *  7 license       00000004  0000000000000000  0000000000000000  00000988  2**0
+ *                  CONTENTS, ALLOC, LOAD, DATA
+ *  [...]
+ *  # echo 1 > /proc/sys/net/core/bpf_jit_enable
+ *  $ gcc bpf_agent.c -o bpf_agent -Wall -O2
+ *  # ./bpf_agent /tmp/bpf-uds      (e.g. on a different terminal)
+ *  # tc filter add dev em1 parent 1: bpf obj bpf.o exp /tmp/bpf-uds flowid 1:1 \
+ *                             action bpf obj bpf.o sec action-mark            \
+ *                             action bpf obj bpf.o sec action-rand ok
+ *  # tc filter show dev em1
+ *  filter parent 1: protocol all pref 49152 bpf
+ *  filter parent 1: protocol all pref 49152 bpf handle 0x1 flowid 1:1 bpf.o:[classifier]
+ *    action order 1: bpf bpf.o:[action-mark] default-action pipe
+ *    index 52 ref 1 bind 1
+ *
+ *    action order 2: bpf bpf.o:[action-rand] default-action pipe
+ *    index 53 ref 1 bind 1
+ *
+ *    action order 3: gact action pass
+ *    random type none pass val 0
+ *    index 38 ref 1 bind 1
+ *
+ * The same program can also be installed on ingress side (as opposed to above
+ * egress configuration), e.g.:
+ *
+ * # tc qdisc add dev em1 handle ffff: ingress
+ * # tc filter add dev em1 parent ffff: bpf obj ...
+ *
+ * Notes on BPF agent:
+ *
+ * In the above example, the bpf_agent creates the unix domain socket
+ * natively. "tc exec" can also spawn a shell and hold the socktes there:
+ *
+ *  # tc exec bpf imp /tmp/bpf-uds
+ *  # tc filter add dev em1 parent 1: bpf obj bpf.o exp /tmp/bpf-uds flowid 1:1 \
+ *                             action bpf obj bpf.o sec action-mark            \
+ *                             action bpf obj bpf.o sec action-rand ok
+ *  sh-4.2# (shell spawned from tc exec)
+ *  sh-4.2# bpf_agent
+ *  [...]
+ *
+ * This will read out fds over environment and produce the same data dump
+ * as below. This has the advantage that the spawned shell owns the fds
+ * and thus if the agent is restarted, it can reattach to the same fds, also
+ * various programs can easily read/modify the data simultaneously from user
+ * space side.
+ *
+ * If the shell is unnecessary, the agent can also just be spawned directly
+ * via tc exec:
+ *
+ *  # tc exec bpf imp /tmp/bpf-uds run bpf_agent
+ *  # tc filter add dev em1 parent 1: bpf obj bpf.o exp /tmp/bpf-uds flowid 1:1 \
+ *                             action bpf obj bpf.o sec action-mark            \
+ *                             action bpf obj bpf.o sec action-rand ok
+ *
+ * BPF agent example output:
+ *
+ * ver: 1
+ * obj: bpf.o
+ * dev: 64770
+ * ino: 6045133
+ * maps: 3
+ * map0:
+ *  `- fd: 4
+ *   | serial: 1
+ *   | type: 1
+ *   | max elem: 256
+ *   | size key: 1
+ *   ` size val: 16
+ * map1:
+ *  `- fd: 5
+ *   | serial: 2
+ *   | type: 1
+ *   | max elem: 1024
+ *   | size key: 4
+ *   ` size val: 16
+ * map2:
+ *  `- fd: 6
+ *   | serial: 3
+ *   | type: 2
+ *   | max elem: 64
+ *   | size key: 4
+ *   ` size val: 8
+ * data, period: 5sec
+ *  `- number of drops:	cpu0:     0	cpu1:     0	cpu2:     0	cpu3:     0
+ *   | nic queues:	q0:[pkts: 0, mis: 0]	q1:[pkts: 0, mis: 0]	q2:[pkts: 0, mis: 0]	q3:[pkts: 0, mis: 0]
+ *   ` protos:	tcp:[pkts: 0, bytes: 0]	udp:[pkts: 0, bytes: 0]	icmp:[pkts: 0, bytes: 0]
+ * data, period: 5sec
+ *  `- number of drops:	cpu0:     5	cpu1:     0	cpu2:     0	cpu3:     1
+ *   | nic queues:	q0:[pkts: 0, mis: 0]	q1:[pkts: 0, mis: 0]	q2:[pkts: 24, mis: 14]	q3:[pkts: 0, mis: 0]
+ *   ` protos:	tcp:[pkts: 13, bytes: 1989]	udp:[pkts: 10, bytes: 710]	icmp:[pkts: 0, bytes: 0]
+ * data, period: 5sec
+ *  `- number of drops:	cpu0:     5	cpu1:     0	cpu2:     3	cpu3:     3
+ *   | nic queues:	q0:[pkts: 0, mis: 0]	q1:[pkts: 0, mis: 0]	q2:[pkts: 39, mis: 21]	q3:[pkts: 0, mis: 0]
+ *   ` protos:	tcp:[pkts: 20, bytes: 3549]	udp:[pkts: 18, bytes: 1278]	icmp:[pkts: 0, bytes: 0]
+ * [...]
+ *
+ * This now means, the below classifier and action pipeline has been loaded
+ * as eBPF bytecode into the kernel, the kernel has verified that the
+ * execution of the bytecode is "safe", and it has JITed the programs
+ * afterwards, so that upon invocation they're running on native speed. tc
+ * has transferred all map file descriptors to the bpf_agent via IPC and
+ * even after tc exits, the agent can read out or modify all map data.
+ *
+ * Note that the export to the uds is done only once in the classifier and
+ * not in the action. It's enough to export the (here) shared descriptors
+ * once.
+ *
+ * If you need to disassemble the generated JIT image (echo with 2), the
+ * kernel tree has under tools/net/ a small helper, you can invoke e.g.
+ * `bpf_jit_disasm -o`.
+ *
+ * Please find in the code below further comments.
+ *
+ *   -- Happy eBPF hacking! ;)
+ */
+#include <stdint.h>
+#include <stdbool.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <asm/types.h>
+#include <linux/in.h>
+#include <linux/if.h>
+#include <linux/if_ether.h>
+#include <linux/ip.h>
+#include <linux/ipv6.h>
+#include <linux/if_tunnel.h>
+#include <linux/filter.h>
+#include <linux/bpf.h>
+
+/* Common, shared definitions with ebpf_agent.c. */
+#include "bpf_shared.h"
+/* BPF helper functions for our example. */
+#include "../../include/bpf_api.h"
+
+/* Could be defined here as well, or included from the header. */
+#define TC_ACT_UNSPEC		(-1)
+#define TC_ACT_OK		0
+#define TC_ACT_RECLASSIFY	1
+#define TC_ACT_SHOT		2
+#define TC_ACT_PIPE		3
+#define TC_ACT_STOLEN		4
+#define TC_ACT_QUEUED		5
+#define TC_ACT_REPEAT		6
+
+/* Other, misc stuff. */
+#define IP_MF			0x2000
+#define IP_OFFSET		0x1FFF
+
+/* eBPF map definitions, all placed in section "maps". */
+struct bpf_elf_map __section("maps") map_proto = {
+	.type		=	BPF_MAP_TYPE_HASH,
+	.id		=	BPF_MAP_ID_PROTO,
+	.size_key	=	sizeof(uint8_t),
+	.size_value	=	sizeof(struct count_tuple),
+	.max_elem	=	256,
+};
+
+struct bpf_elf_map __section("maps") map_queue = {
+	.type		=	BPF_MAP_TYPE_HASH,
+	.id		=	BPF_MAP_ID_QUEUE,
+	.size_key	=	sizeof(uint32_t),
+	.size_value	=	sizeof(struct count_queue),
+	.max_elem	=	1024,
+};
+
+struct bpf_elf_map __section("maps") map_drops = {
+	.type		=	BPF_MAP_TYPE_ARRAY,
+	.id		=	BPF_MAP_ID_DROPS,
+	.size_key	=	sizeof(uint32_t),
+	.size_value	=	sizeof(long),
+	.max_elem	=	64,
+};
+
+/* Helper functions and definitions for the flow dissector used by the
+ * example classifier. This resembles the kernel's flow dissector to
+ * some extend and is just used as an example to show what's possible
+ * with eBPF.
+ */
+struct sockaddr;
+
+struct vlan_hdr {
+	__be16 h_vlan_TCI;
+	__be16 h_vlan_encapsulated_proto;
+};
+
+struct flow_keys {
+	__u32 src;
+	__u32 dst;
+	union {
+		__u32 ports;
+		__u16 port16[2];
+	};
+	__s32 th_off;
+	__u8 ip_proto;
+};
+
+static inline int flow_ports_offset(__u8 ip_proto)
+{
+	switch (ip_proto) {
+	case IPPROTO_TCP:
+	case IPPROTO_UDP:
+	case IPPROTO_DCCP:
+	case IPPROTO_ESP:
+	case IPPROTO_SCTP:
+	case IPPROTO_UDPLITE:
+	default:
+		return 0;
+	case IPPROTO_AH:
+		return 4;
+	}
+}
+
+static inline bool flow_is_frag(struct __sk_buff *skb, int nh_off)
+{
+	return !!(load_half(skb, nh_off + offsetof(struct iphdr, frag_off)) &
+		  (IP_MF | IP_OFFSET));
+}
+
+static inline int flow_parse_ipv4(struct __sk_buff *skb, int nh_off,
+				  __u8 *ip_proto, struct flow_keys *flow)
+{
+	__u8 ip_ver_len;
+
+	if (unlikely(flow_is_frag(skb, nh_off)))
+		*ip_proto = 0;
+	else
+		*ip_proto = load_byte(skb, nh_off + offsetof(struct iphdr,
+							     protocol));
+	if (*ip_proto != IPPROTO_GRE) {
+		flow->src = load_word(skb, nh_off + offsetof(struct iphdr, saddr));
+		flow->dst = load_word(skb, nh_off + offsetof(struct iphdr, daddr));
+	}
+
+	ip_ver_len = load_byte(skb, nh_off + 0 /* offsetof(struct iphdr, ihl) */);
+	if (likely(ip_ver_len == 0x45))
+		nh_off += 20;
+	else
+		nh_off += (ip_ver_len & 0xF) << 2;
+
+	return nh_off;
+}
+
+static inline __u32 flow_addr_hash_ipv6(struct __sk_buff *skb, int off)
+{
+	__u32 w0 = load_word(skb, off);
+	__u32 w1 = load_word(skb, off + sizeof(w0));
+	__u32 w2 = load_word(skb, off + sizeof(w0) * 2);
+	__u32 w3 = load_word(skb, off + sizeof(w0) * 3);
+
+	return w0 ^ w1 ^ w2 ^ w3;
+}
+
+static inline int flow_parse_ipv6(struct __sk_buff *skb, int nh_off,
+				  __u8 *ip_proto, struct flow_keys *flow)
+{
+	*ip_proto = load_byte(skb, nh_off + offsetof(struct ipv6hdr, nexthdr));
+
+	flow->src = flow_addr_hash_ipv6(skb, nh_off + offsetof(struct ipv6hdr, saddr));
+	flow->dst = flow_addr_hash_ipv6(skb, nh_off + offsetof(struct ipv6hdr, daddr));
+
+	return nh_off + sizeof(struct ipv6hdr);
+}
+
+static inline bool flow_dissector(struct __sk_buff *skb,
+				  struct flow_keys *flow)
+{
+	int poff, nh_off = BPF_LL_OFF + ETH_HLEN;
+	__be16 proto = skb->protocol;
+	__u8 ip_proto;
+
+	/* TODO: check for skb->vlan_tci, skb->vlan_proto first */
+	if (proto == htons(ETH_P_8021AD)) {
+		proto = load_half(skb, nh_off +
+				  offsetof(struct vlan_hdr, h_vlan_encapsulated_proto));
+		nh_off += sizeof(struct vlan_hdr);
+	}
+	if (proto == htons(ETH_P_8021Q)) {
+		proto = load_half(skb, nh_off +
+				  offsetof(struct vlan_hdr, h_vlan_encapsulated_proto));
+		nh_off += sizeof(struct vlan_hdr);
+	}
+
+	if (likely(proto == htons(ETH_P_IP)))
+		nh_off = flow_parse_ipv4(skb, nh_off, &ip_proto, flow);
+	else if (proto == htons(ETH_P_IPV6))
+		nh_off = flow_parse_ipv6(skb, nh_off, &ip_proto, flow);
+	else
+		return false;
+
+	switch (ip_proto) {
+	case IPPROTO_GRE: {
+		struct gre_hdr {
+			__be16 flags;
+			__be16 proto;
+		};
+
+		__u16 gre_flags = load_half(skb, nh_off +
+					    offsetof(struct gre_hdr, flags));
+		__u16 gre_proto = load_half(skb, nh_off +
+					    offsetof(struct gre_hdr, proto));
+
+		if (gre_flags & (GRE_VERSION | GRE_ROUTING))
+			break;
+
+		nh_off += 4;
+		if (gre_flags & GRE_CSUM)
+			nh_off += 4;
+		if (gre_flags & GRE_KEY)
+			nh_off += 4;
+		if (gre_flags & GRE_SEQ)
+			nh_off += 4;
+
+		if (gre_proto == ETH_P_8021Q) {
+			gre_proto = load_half(skb, nh_off +
+					      offsetof(struct vlan_hdr,
+						       h_vlan_encapsulated_proto));
+			nh_off += sizeof(struct vlan_hdr);
+		}
+		if (gre_proto == ETH_P_IP)
+			nh_off = flow_parse_ipv4(skb, nh_off, &ip_proto, flow);
+		else if (gre_proto == ETH_P_IPV6)
+			nh_off = flow_parse_ipv6(skb, nh_off, &ip_proto, flow);
+		else
+			return false;
+		break;
+	}
+	case IPPROTO_IPIP:
+		nh_off = flow_parse_ipv4(skb, nh_off, &ip_proto, flow);
+		break;
+	case IPPROTO_IPV6:
+		nh_off = flow_parse_ipv6(skb, nh_off, &ip_proto, flow);
+	default:
+		break;
+	}
+
+	nh_off += flow_ports_offset(ip_proto);
+
+	flow->ports = load_word(skb, nh_off);
+	flow->th_off = nh_off;
+	flow->ip_proto = ip_proto;
+
+	return true;
+}
+
+static inline void cls_update_proto_map(const struct __sk_buff *skb,
+					const struct flow_keys *flow)
+{
+	uint8_t proto = flow->ip_proto;
+	struct count_tuple *ct, _ct;
+
+	ct = map_lookup_elem(&map_proto, &proto);
+	if (likely(ct)) {
+		lock_xadd(&ct->packets, 1);
+		lock_xadd(&ct->bytes, skb->len);
+		return;
+	}
+
+	/* No hit yet, we need to create a new entry. */
+	_ct.packets = 1;
+	_ct.bytes = skb->len;
+
+	map_update_elem(&map_proto, &proto, &_ct, BPF_ANY);
+}
+
+static inline void cls_update_queue_map(const struct __sk_buff *skb)
+{
+	uint32_t queue = skb->queue_mapping;
+	struct count_queue *cq, _cq;
+	bool mismatch;
+
+	mismatch = skb->queue_mapping != get_smp_processor_id();
+
+	cq = map_lookup_elem(&map_queue, &queue);
+	if (likely(cq)) {
+		lock_xadd(&cq->total, 1);
+		if (mismatch)
+			lock_xadd(&cq->mismatch, 1);
+		return;
+	}
+
+	/* No hit yet, we need to create a new entry. */
+	_cq.total = 1;
+	_cq.mismatch = mismatch ? 1 : 0;
+
+	map_update_elem(&map_queue, &queue, &_cq, BPF_ANY);
+}
+
+/* eBPF program definitions, placed in various sections, which can
+ * have custom section names. If custom names are in use, it's
+ * required to point tc to the correct section, e.g.
+ *
+ *     tc filter add [...] bpf obj cls.o sec cls-tos [...]
+ *
+ * in case the program resides in __section("cls-tos").
+ *
+ * Default section for cls_bpf is: "classifier", for act_bpf is:
+ * "action". Naturally, if for example multiple actions are present
+ * in the same file, they need to have distinct section names.
+ *
+ * It is however not required to have multiple programs sharing
+ * a file.
+ */
+__section("classifier")
+int cls_main(struct __sk_buff *skb)
+{
+	struct flow_keys flow;
+
+	if (!flow_dissector(skb, &flow))
+		return 0; /* No match in cls_bpf. */
+
+	cls_update_proto_map(skb, &flow);
+	cls_update_queue_map(skb);
+
+	return flow.ip_proto;
+}
+
+static inline void act_update_drop_map(void)
+{
+	uint32_t *count, cpu = get_smp_processor_id();
+
+	count = map_lookup_elem(&map_drops, &cpu);
+	if (count)
+		/* Only this cpu is accessing this element. */
+		(*count)++;
+}
+
+__section("action-mark")
+int act_mark_main(struct __sk_buff *skb)
+{
+	/* You could also mangle skb data here with the helper function
+	 * BPF_FUNC_skb_store_bytes, etc. Or, alternatively you could
+	 * do that already in the classifier itself as a merged combination
+	 * of classifier'n'action model.
+	 */
+
+	if (skb->mark == 0xcafe) {
+		act_update_drop_map();
+		return TC_ACT_SHOT;
+	}
+
+	/* Default configured tc opcode. */
+	return TC_ACT_UNSPEC;
+}
+
+__section("action-rand")
+int act_rand_main(struct __sk_buff *skb)
+{
+	/* Sorry, we're near event horizon ... */
+	if ((get_prandom_u32() & 3) == 0) {
+		act_update_drop_map();
+		return TC_ACT_SHOT;
+	}
+
+	return TC_ACT_UNSPEC;
+}
+
+/* Last but not least, the file contains a license. Some future helper
+ * functions may only be available with a GPL license.
+ */
+BPF_LICENSE("GPL");
diff --git a/iproute2/examples/bpf/bpf_shared.c b/iproute2/examples/bpf/bpf_shared.c
new file mode 100644
index 0000000..accc0ad
--- /dev/null
+++ b/iproute2/examples/bpf/bpf_shared.c
@@ -0,0 +1,48 @@
+#include "../../include/bpf_api.h"
+
+/* Minimal, stand-alone toy map pinning example:
+ *
+ * clang -target bpf -O2 [...] -o bpf_shared.o -c bpf_shared.c
+ * tc filter add dev foo parent 1: bpf obj bpf_shared.o sec egress
+ * tc filter add dev foo parent ffff: bpf obj bpf_shared.o sec ingress
+ *
+ * Both classifier will share the very same map instance in this example,
+ * so map content can be accessed from ingress *and* egress side!
+ *
+ * This example has a pinning of PIN_OBJECT_NS, so it's private and
+ * thus shared among various program sections within the object.
+ *
+ * A setting of PIN_GLOBAL_NS would place it into a global namespace,
+ * so that it can be shared among different object files. A setting
+ * of PIN_NONE (= 0) means no sharing, so each tc invocation a new map
+ * instance is being created.
+ */
+
+BPF_ARRAY4(map_sh, 0, PIN_OBJECT_NS, 1); /* or PIN_GLOBAL_NS, or PIN_NONE */
+
+__section("egress")
+int emain(struct __sk_buff *skb)
+{
+	int key = 0, *val;
+
+	val = map_lookup_elem(&map_sh, &key);
+	if (val)
+		lock_xadd(val, 1);
+
+	return BPF_H_DEFAULT;
+}
+
+__section("ingress")
+int imain(struct __sk_buff *skb)
+{
+	char fmt[] = "map val: %d\n";
+	int key = 0, *val;
+
+	val = map_lookup_elem(&map_sh, &key);
+	if (val)
+		trace_printk(fmt, sizeof(fmt), *val);
+
+	return BPF_H_DEFAULT;
+}
+
+BPF_LICENSE("GPL");
diff --git a/iproute2/examples/bpf/bpf_shared.h b/iproute2/examples/bpf/bpf_shared.h
new file mode 100644
index 0000000..a24038d
--- /dev/null
+++ b/iproute2/examples/bpf/bpf_shared.h
@@ -0,0 +1,22 @@
+#ifndef __BPF_SHARED__
+#define __BPF_SHARED__
+
+enum {
+	BPF_MAP_ID_PROTO,
+	BPF_MAP_ID_QUEUE,
+	BPF_MAP_ID_DROPS,
+	__BPF_MAP_ID_MAX,
+#define BPF_MAP_ID_MAX	__BPF_MAP_ID_MAX
+};
+
+struct count_tuple {
+	long packets; /* type long for lock_xadd() */
+	long bytes;
+};
+
+struct count_queue {
+	long total;
+	long mismatch;
+};
+
+#endif /* __BPF_SHARED__ */
diff --git a/iproute2/examples/bpf/bpf_sys.h b/iproute2/examples/bpf/bpf_sys.h
new file mode 100644
index 0000000..6e4f09e
--- /dev/null
+++ b/iproute2/examples/bpf/bpf_sys.h
@@ -0,0 +1,23 @@
+#ifndef __BPF_SYS__
+#define __BPF_SYS__
+
+#include <sys/syscall.h>
+#include <linux/bpf.h>
+
+static inline __u64 bpf_ptr_to_u64(const void *ptr)
+{
+	return (__u64) (unsigned long) ptr;
+}
+
+static inline int bpf_lookup_elem(int fd, void *key, void *value)
+{
+	union bpf_attr attr = {
+		.map_fd		= fd,
+		.key		= bpf_ptr_to_u64(key),
+		.value		= bpf_ptr_to_u64(value),
+	};
+
+	return syscall(__NR_bpf, BPF_MAP_LOOKUP_ELEM, &attr, sizeof(attr));
+}
+
+#endif /* __BPF_SYS__ */
diff --git a/iproute2/examples/bpf/bpf_tailcall.c b/iproute2/examples/bpf/bpf_tailcall.c
new file mode 100644
index 0000000..040790d
--- /dev/null
+++ b/iproute2/examples/bpf/bpf_tailcall.c
@@ -0,0 +1,99 @@
+#include "../../include/bpf_api.h"
+
+#define ENTRY_INIT	3
+#define ENTRY_0		0
+#define ENTRY_1		1
+#define MAX_JMP_SIZE	2
+
+#define FOO		42
+#define BAR		43
+
+/* This example doesn't really do anything useful, but it's purpose is to
+ * demonstrate eBPF tail calls on a very simple example.
+ *
+ * cls_entry() is our classifier entry point, from there we jump based on
+ * skb->hash into cls_case1() or cls_case2(). They are both part of the
+ * program array jmp_tc. Indicated via __section_tail(), the tc loader
+ * populates the program arrays with the loaded file descriptors already.
+ *
+ * To demonstrate nested jumps, cls_case2() jumps within the same jmp_tc
+ * array to cls_case1(). And whenever we arrive at cls_case1(), we jump
+ * into cls_exit(), part of the jump array jmp_ex.
+ *
+ * Also, to show it's possible, all programs share map_sh and dump the value
+ * that the entry point incremented. The sections that are loaded into a
+ * program array can be atomically replaced during run-time, e.g. to change
+ * classifier behaviour.
+ */
+
+BPF_PROG_ARRAY(jmp_tc, FOO, PIN_OBJECT_NS, MAX_JMP_SIZE);
+BPF_PROG_ARRAY(jmp_ex, BAR, PIN_OBJECT_NS, 1);
+
+BPF_ARRAY4(map_sh, 0, PIN_OBJECT_NS, 1);
+
+__section_tail(FOO, ENTRY_0)
+int cls_case1(struct __sk_buff *skb)
+{
+	char fmt[] = "case1: map-val: %d from:%u\n";
+	int key = 0, *val;
+
+	val = map_lookup_elem(&map_sh, &key);
+	if (val)
+		trace_printk(fmt, sizeof(fmt), *val, skb->cb[0]);
+
+	skb->cb[0] = ENTRY_0;
+	tail_call(skb, &jmp_ex, ENTRY_0);
+
+	return BPF_H_DEFAULT;
+}
+
+__section_tail(FOO, ENTRY_1)
+int cls_case2(struct __sk_buff *skb)
+{
+	char fmt[] = "case2: map-val: %d from:%u\n";
+	int key = 0, *val;
+
+	val = map_lookup_elem(&map_sh, &key);
+	if (val)
+		trace_printk(fmt, sizeof(fmt), *val, skb->cb[0]);
+
+	skb->cb[0] = ENTRY_1;
+	tail_call(skb, &jmp_tc, ENTRY_0);
+
+	return BPF_H_DEFAULT;
+}
+
+__section_tail(BAR, ENTRY_0)
+int cls_exit(struct __sk_buff *skb)
+{
+	char fmt[] = "exit: map-val: %d from:%u\n";
+	int key = 0, *val;
+
+	val = map_lookup_elem(&map_sh, &key);
+	if (val)
+		trace_printk(fmt, sizeof(fmt), *val, skb->cb[0]);
+
+	/* Termination point. */
+	return BPF_H_DEFAULT;
+}
+
+__section_cls_entry
+int cls_entry(struct __sk_buff *skb)
+{
+	char fmt[] = "fallthrough\n";
+	int key = 0, *val;
+
+	/* For transferring state, we can use skb->cb[0] ... skb->cb[4]. */
+	val = map_lookup_elem(&map_sh, &key);
+	if (val) {
+		lock_xadd(val, 1);
+
+		skb->cb[0] = ENTRY_INIT;
+		tail_call(skb, &jmp_tc, skb->hash & (MAX_JMP_SIZE - 1));
+	}
+
+	trace_printk(fmt, sizeof(fmt));
+	return BPF_H_DEFAULT;
+}
+
+BPF_LICENSE("GPL");
diff --git a/iproute2/examples/cbq.init-v0.7.3 b/iproute2/examples/cbq.init-v0.7.3
new file mode 100644
index 0000000..1bc0d44
--- /dev/null
+++ b/iproute2/examples/cbq.init-v0.7.3
@@ -0,0 +1,983 @@
+#!/bin/bash
+#
+#    cbq.init v0.7.3
+#    Copyright (C) 1999  Pavel Golubev <pg@ksi-linux.com>
+#    Copyright (C) 2001-2004  Lubomir Bulej <pallas@kadan.cz>
+#
+#    chkconfig:   2345 11 89
+#    description: sets up CBQ-based traffic control
+#
+#    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, see <http://www.gnu.org/licenses/>.
+#
+#    To get the latest version, check on Freshmeat for actual location:
+#
+#		http://freshmeat.net/projects/cbq.init
+#
+#
+# VERSION HISTORY
+# ---------------
+# v0.7.3- Deepak Singhal <singhal at users.sourceforge.net>
+#	  - fix timecheck to not ignore regular TIME rules after
+#	    encountering a TIME rule that spans over midnight
+#	- Nathan Shafer <nicodemus at users.sourceforge.net>
+#	  - allow symlinks to class files
+#	- Seth J. Blank <antifreeze at users.sourceforge.net>
+#	  - replace hardcoded ip/tc location with variables
+#	- Mark Davis <mark.davis at gmx.de>
+#	  - allow setting of PRIO_{MARK,RULE,REALM} in class file
+#	- Fernando Sanch <toptnc at users.sourceforge.net>
+#	  - allow underscores in interface names
+# v0.7.2- Paulo Sedrez
+#	  - fix time2abs to allow hours with leading zero in TIME rules
+#	- Svetlin Simeonov <zvero at yahoo.com>
+#	  - fix cbq_device_list to allow VLAN interfaces
+#	- Mark Davis <mark.davis at gmx.de>
+#	  - ignore *~ backup files when looking for classes
+#	- Mike Boyer <boyer at administrative.com>
+#	  - fix to allow arguments to be passed to "restart" command
+# v0.7.1- Lubomir Bulej <pallas at kadan.cz>
+#	  - default value for PERTURB
+#	  - fixed small bug in RULE parser to correctly parse rules with
+#	    identical source and destination fields
+#	  - faster initial scanning of DEVICE fields
+# v0.7	- Lubomir Bulej <pallas at kadan.cz>
+#	  - lots of various cleanups and reorganizations; the parsing is now
+#	    some 40% faster, but the class ID must be in range 0x0002-0xffff
+#	    (again). Because of the number of internal changes and the above
+#	    class ID restriction, I bumped the version to 0.7 to indicate
+#	    something might have got broken :)
+#	  - changed PRIO_{U32,FW,ROUTE} to PRIO_{RULE,MARK,REALM}
+#	    for consistency with filter keywords
+#	  - exposed "compile" command
+#	- Catalin Petrescu <taz at dntis.ro>
+#	  - support for port masks in RULE (u32) filter
+#	- Jordan Vrtanoski <obeliks at mt.net.mk>
+#	  - support for week days in TIME rules
+# v0.6.4- Lubomir Bulej <pallas at kadan.cz>
+#	  - added PRIO_* variables to allow easy control of filter priorities
+#	  - added caching to speed up CBQ start, the cache is invalidated
+#	    whenever any of the configuration files changes
+#	  - updated the readme section + some cosmetic fixes
+# v0.6.3- Lubomir Bulej <pallas at kadan.cz>
+#	  - removed setup of (unnecessary) class 1:1 - all classes
+#	    now use qdisc's default class 1:0 as their parent
+#	  - minor fix in the timecheck branch - classes
+#	    without leaf qdisc were not updated
+#	  - minor fix to avoid timecheck failure when run
+#	    at time with minutes equal to 08 or 09
+#	  - respect CBQ_PATH setting in environment
+#	  - made PRIO=5 default, rendering it optional in configs
+#	  - added support for route filter, see notes about REALM keyword
+#	  - added support for fw filter, see notes about MARK keyword
+#	  - added filter display to "list" and "stats" commands
+#	  - readme section update + various cosmetic fixes
+# v0.6.2- Catalin Petrescu <taz at dntis.ro>
+#	  - added tunnels interface handling
+# v0.6.1- Pavel Golubev <pg at ksi-linux.com>
+#	  - added sch_prio module loading
+#	    (thanks johan at iglo.virtual.or.id for reminding)
+#	  - resolved errors resulting from stricter syntax checking in bash2
+#	- Lubomir Bulej <pallas at kadan.cz>
+#	  - various cosmetic fixes
+# v0.6	- Lubomir Bulej <pallas at kadan.cz>
+#	  - attempt to limit number of spawned processes by utilizing
+#	    more of sed power (use sed instead of grep+cut)
+#	  - simplified TIME parser, using bash builtins
+#	  - added initial support for SFQ as leaf qdisc
+#	  - reworked the documentation part a little
+#	  - incorporated pending patches and ideas submitted by
+#	    following people for versions 0.3 into version 0.6
+#	- Miguel Freitas <miguel at cetuc.puc-rio.br>
+#	  - in case of overlapping TIME parameters, the last match is taken
+#	- Juanjo Ciarlante <jjo at mendoza.gov.ar>
+#	  - chkconfig tags, list + stats startup parameters
+#	  - optional tc & ip command logging (into /var/run/cbq-*)
+#	- Rafal Maszkowski <rzm at icm.edu.pl>
+#	  - PEAK parameter for setting TBF's burst peak rate
+#	  - fix for many config files (use find instead of ls)
+# v0.5.1- Lubomir Bulej <pallas at kadan.cz>
+#	  - fixed little but serious bug in RULE parser
+# v0.5	- Lubomir Bulej <pallas at kadan.cz>
+#	  - added options PARENT, LEAF, ISOLATED and BOUNDED. This allows
+#	    (with some attention to config file ordering) for creating
+#	    hierarchical structures of shapers with classes able (or unable)
+#	    to borrow bandwidth from their parents.
+#	  - class ID check allows hexadecimal numbers
+#	  - rewritten & simplified RULE parser
+#	  - cosmetic changes to improve readability
+#	  - reorganization to avoid duplicate code (timecheck etc.)
+#	  - timecheck doesn't check classes without TIME fields anymore
+# v0.4  - Lubomir Bulej <pallas at kadan.cz>
+#	  - small bugfix in RULE parsing code
+#	  - simplified configuration parsing code
+#	  - several small cosmetic changes
+#	  - TIME parameter can be now specified more than once allowing you to
+#	    differentiate RATE throughout the whole day. Time overlapping is
+#	    not checked, first match is taken. Midnight wrap (eg. 20:00-6:00)
+#	    is allowed and taken care of.
+# v0.3a4- fixed small bug in IF operator. Thanks to
+#	  Rafal Maszkowski <rzm at icm.edu.pl>
+# v0.3a3- fixed grep bug when using more than 10 eth devices. Thanks to David
+#	  Trcka <trcka at poda.cz>.
+# v0.3a2- fixed bug in "if" operator. Thanks kad at dgtu.donetsk.ua.
+# v0.3a - added TIME parameter. Example: TIME=00:00-19:00;64Kbit/6Kbit
+#	  So, between 00:00 and 19:00 the RATE will be 64Kbit.
+#	  Just start "cbq.init timecheck" periodically from cron
+#	  (every 10 minutes for example). DON'T FORGET though, to run
+#	  "cbq.init start" for CBQ to initialize.
+# v0.2  - Some cosmetic changes. Now it is more compatible with old bash
+#	  version. Thanks to Stanislav V. Voronyi <stas at cnti.uanet.kharkov.ua>.
+# v0.1  - First public release
+#
+#
+# README
+# ------
+#
+# First of all - this is just a SIMPLE EXAMPLE of CBQ power.
+# Don't ask me "why" and "how" :)
+#
+# This script is meant to simplify setup and management of relatively simple
+# CBQ-based traffic control on Linux. Access to advanced networking features
+# of Linux kernel is provided by "ip" and "tc" utilities from A. Kuznetsov's
+# iproute2 package, available at ftp://ftp.inr.ac.ru/ip-routing. Because the
+# utilities serve primarily to translate user wishes to RTNETLINK commands,
+# their interface is rather spartan, intolerant and requires quite a lot of
+# typing. And typing is what this script attempts to reduce :)
+#
+# The advanced networking stuff in Linux is pretty flexible and this script
+# aims to bring some of its features to the not-so-hard-core Linux users. Of
+# course, there is a tradeoff between simplicity and flexibility and you may
+# realize that the flexibility suffered too much for your needs -- time to
+# face "ip" and "tc" interface.
+#
+# To speed up the "start" command, simple caching was introduced in version
+# 0.6.4. The caching works so that the sequence of "tc" commands for given
+# configuration is stored in a file (/var/cache/cbq.init by default) which
+# is used next time the "start" command is run to avoid repeated parsing of
+# configuration files. This cache is invalidated whenever any of the CBQ
+# configuration files changes. If you want to run "cbq.init start" without
+# caching, run it as "cbq.init start nocache". If you want to force cache
+# invalidation, run it as "cbq.init start invalidate". Caching is disabled
+# if you have logging enabled (ie. CBQ_DEBUG is not empty).
+#
+# If you only want cqb.init to translate your configuration to "tc" commands,
+# use "compile" command which will output "tc" commands required to build
+# your configuration. Bear in mind that "compile" does not check if the "tc"
+# commands were successful - this is done (in certain places) only when the
+# "start nocache" command is used, which is also useful when creating the
+# configuration to check whether it is completely valid.
+#
+# All CBQ parameters are valid for Ethernet interfaces only, The script was
+# tested on various Linux kernel versions from series 2.1 to 2.4 and several
+# distributions with KSI Linux (Nostromo version) as the premier one.
+#
+#
+# HOW DOES IT WORK?
+# -----------------
+#
+# Every traffic class must be described by a file in the $CBQ_PATH directory
+# (/etc/sysconfig/cbq by default) - one file per class.
+#
+# The config file names must obey mandatory format: cbq-<clsid>.<name> where
+# <clsid> is two-byte hexadecimal number in range <0002-FFFF> (which in fact
+# is a CBQ class ID) and <name> is the name of the class -- anything to help
+# you distinguish the configuration files. For small amount of classes it is
+# often possible (and convenient) to let <clsid> resemble bandwidth of the
+# class.
+#
+# Example of valid config name:
+#	cbq-1280.My_first_shaper
+#
+#
+# The configuration file may contain the following parameters:
+#
+### Device parameters
+#
+# DEVICE=<ifname>,<bandwidth>[,<weight>]	mandatory
+# DEVICE=eth0,10Mbit,1Mbit
+#
+#	<ifname> is the name of the interface you want to control
+#		traffic on, e.g. eth0
+#	<bandwidth> is the physical bandwidth of the device, e.g. for
+#		ethernet 10Mbit or 100Mbit, for arcnet 2Mbit
+#	<weight> is tuning parameter that should be proportional to
+#		<bandwidth>. As a rule of thumb: <weight> = <bandwidth> / 10
+#
+# When you have more classes on one interface, it is enough to specify
+# <bandwidth> [and <weight>] only once, therefore in other files you only
+# need to set DEVICE=<ifname>.
+#
+### Class parameters
+#
+# RATE=<speed>					mandatory
+# RATE=5Mbit
+#
+#	Bandwidth allocated to the class. Traffic going through the class is
+#	shaped to conform to specified rate. You can use Kbit, Mbit or bps,
+#	Kbps and Mbps as suffices. If you don't specify any unit, bits/sec
+#	are used. Also note that "bps" means "bytes per second", not bits.
+#
+# WEIGHT=<speed> 				mandatory
+# WEIGHT=500Kbit
+#
+#	Tuning parameter that should be proportional to RATE. As a rule
+#	of thumb, use WEIGHT ~= RATE / 10.
+#
+# PRIO=<1-8>					optional, default 5
+# PRIO=5
+#
+#	Priority of class traffic. The higher the number, the lesser
+#	the priority. Priority of 5 is just fine.
+#
+# PARENT=<clsid>				optional, default not set
+# PARENT=1280
+#
+#	Specifies ID of the parent class to which you want this class be
+#	attached. You might want to use LEAF=none for the parent class as
+#	mentioned below. By using this parameter and carefully ordering the
+#	configuration files, it is possible to create simple hierarchical
+#	structures of CBQ classes. The ordering is important so that parent
+#	classes are constructed prior to their children.
+#
+# LEAF=none|tbf|sfq				optional, default "tbf"
+#
+#	Tells the script to attach specified leaf queueing discipline to CBQ
+#	class. By default, TBF is used. Note that attaching TBF to CBQ class
+#	shapes the traffic to conform to TBF parameters and prevents the class
+#	from borrowing bandwidth from its parent even if you have BOUNDED set
+#	to "no". To allow the class to borrow bandwith (provided it is not
+#	bounded), you must set LEAF to "none" or "sfq".
+#
+#	If you want to ensure (approximately) fair sharing of bandwidth among
+#	several hosts in the same class, you might want to specify LEAF=sfq to
+#	attach SFQ as leaf queueing discipline to that class.
+#
+# BOUNDED=yes|no				optional, default "yes"
+#
+#	If set to "yes", the class is not allowed to borrow bandwidth from
+#	its parent class in overlimit situation. If set to "no", the class
+#	will be allowed to borrow bandwidth from its parent.
+#
+# Note:	Don't forget to set LEAF to "none" or "sfq", otherwise the class will
+#	have TBF attached to itself and will not be able to borrow unused
+#	bandwith from its parent.
+#
+# ISOLATED=yes|no				optional, default "no"
+#
+#	If set to "yes", the class will not lend unused bandwidth to
+#	its children.
+#
+### TBF qdisc parameters
+#
+# BUFFER=<bytes>[/<bytes>]			optional, default "10Kb/8"
+#
+#	This parameter controls the depth of the token bucket. In other
+#	words it represents the maximal burst size the class can send.
+#	The optional part of parameter is used to determine the length
+#	of intervals in packet sizes, for which the transmission times
+#	are kept.
+#
+# LIMIT=<bytes>					optional, default "15Kb"
+#
+#	This parameter determines the maximal length of backlog. If
+#	the queue contains more data than specified by LIMIT, the
+#	newly arriving packets are dropped. The length of backlog
+#	determines queue latency in case of congestion.
+#
+# PEAK=<speed>					optional, default not set
+#
+#	Maximal peak rate for short-term burst traffic. This allows you
+#	to control the absolute peak rate the class can send at, because
+#	single TBF that allows 256Kbit/s would of course allow rate of
+#	512Kbit for half a second or 1Mbit for a quarter of second.
+#
+# MTU=<bytes>  					optional, default "1500"
+#
+#	Maximum number of bytes that can be sent at once over the
+#	physical medium. This parameter is required when you specify
+#	PEAK parameter. It defaults to MTU of ethernet - for other
+#	media types you might want to change it.
+#
+# Note: Setting TBF as leaf qdisc will effectively prevent the class from
+#	borrowing bandwidth from the ancestor class, because even if the
+#	class allows more traffic to pass through, it is then shaped to
+#	conform to TBF.
+#
+### SFQ qdisc parameters
+#
+# The SFQ queueing discipline is a cheap way for sharing class bandwidth
+# among several hosts. As it is stochastic, the fairness is approximate but
+# it will do the job in most cases. If you want real fairness, you should
+# probably use WRR (weighted round robin) or WFQ queueing disciplines. Note
+# that SFQ does not do any traffic shaping - the shaping is done by the CBQ
+# class the SFQ is attached to.
+#
+# QUANTUM=<bytes>				optional, default not set
+#
+#	This parameter should not be set lower than link MTU, for ethernet
+#	it is 1500b, or (with MAC header) 1514b which is the value used
+#	in Alexey Kuznetsov's examples.
+#
+# PERTURB=<seconds>				optional, default "10"
+#
+#	Period of hash function perturbation. If unset, hash reconfiguration
+#	will never take place which is what you probably don't want. The
+#	default value of 10 seconds is probably a good one.
+#
+### Filter parameters
+#
+# RULE=[[saddr[/prefix]][:port[/mask]],][daddr[/prefix]][:port[/mask]]
+#
+#	These parameters make up "u32" filter rules that select traffic for
+#	each of the classes. You can use multiple RULE fields per config.
+#
+#	The optional port mask should only be used by advanced users who
+#	understand how the u32 filter works.
+#
+# Some examples:
+#
+#	RULE=10.1.1.0/24:80
+#		selects traffic going to port 80 in network 10.1.1.0
+#
+#	RULE=10.2.2.5
+#		selects traffic going to any port on single host 10.2.2.5
+#
+#	RULE=10.2.2.5:20/0xfffe
+#		selects traffic going to ports 20 and 21 on host 10.2.2.5
+#
+#	RULE=:25,10.2.2.128/26:5000
+#		selects traffic going from anywhere on port 50 to
+#		port 5000 in network 10.2.2.128
+#
+#	RULE=10.5.5.5:80,
+#		selects traffic going from port 80 of single host 10.5.5.5
+#
+#
+#
+# REALM=[srealm,][drealm]
+#
+#	These parameters make up "route" filter rules that classify traffic
+#	according to packet source/destination realms. For information about
+#	realms, see Alexey Kuznetsov's IP Command Reference. This script
+#	does not define any realms, it justs builds "tc filter" commands
+#	for you if you need to classify traffic this way.
+#
+#	Realm is either a decimal number or a string referencing entry in
+#	/etc/iproute2/rt_realms (usually).
+#
+# Some examples:
+#
+#	REALM=russia,internet
+#		selects traffic going from realm "russia" to realm "internet"
+#
+#	REALM=freenet,
+#		selects traffic going from realm "freenet"
+#
+#	REALM=10
+#		selects traffic going to realm 10
+#
+#
+#
+# MARK=<mark>
+#
+#	These parameters make up "fw" filter rules that select traffic for
+#	each of the classes accoring to firewall "mark". Mark is a decimal
+#	number packets are tagged with if firewall rules say so. You can
+#	use multiple MARK fields per config.
+#
+#
+# Note: Rules for different filter types can be combined. Attention must be
+#	paid to the priority of filter rules, which can be set below using
+#	PRIO_{RULE,MARK,REALM} variables.
+#
+### Time ranging parameters
+#
+# TIME=[<dow>,<dow>, ...,<dow>/]<from>-<till>;<rate>/<weight>[/<peak>]
+# TIME=0,1,2,5/18:00-06:00;256Kbit/25Kbit
+# TIME=60123/18:00-06:00;256Kbit/25Kbit
+# TIME=18:00-06:00;256Kbit/25Kbit
+#
+#	This parameter allows you to differentiate the class bandwidth
+#	throughout the day. You can specify multiple TIME parameters, if
+#	the times overlap, last match is taken. The fields <rate>, <weight>
+#	and <peak> correspond to parameters RATE, WEIGHT and PEAK (which
+#	is optional and applies to TBF leaf qdisc only).
+#
+#	You can also specify days of week when the TIME rule applies. <dow>
+#	is numeric, 0 corresponds to sunday, 1 corresponds to monday, etc.
+#
+###
+#
+# Sample configuration file: cbq-1280.My_first_shaper
+#
+# --------------------------------------------------------------------------
+# DEVICE=eth0,10Mbit,1Mbit
+# RATE=128Kbit
+# WEIGHT=10Kbit
+# PRIO=5
+# RULE=192.128.1.0/24
+# --------------------------------------------------------------------------
+#
+# The configuration says that we will control traffic on 10Mbit ethernet
+# device eth0 and the traffic going to network 192.168.1.0 will be
+# processed with priority 5 and shaped to rate of 128Kbit.
+#
+# Note that you can control outgoing traffic only. If you want to control
+# traffic in both directions, you must set up CBQ for both interfaces.
+#
+# Consider the following example:
+#
+#                    +---------+      192.168.1.1
+# BACKBONE -----eth0-|  linux  |-eth1------*-[client]
+#                    +---------+
+#
+# Imagine you want to shape traffic from backbone to the client to 28Kbit
+# and traffic in the opposite direction to 128Kbit. You need to setup CBQ
+# on both eth0 and eth1 interfaces, thus you need two config files:
+#
+# cbq-028.backbone-client
+# --------------------------------------------------------------------------
+# DEVICE=eth1,10Mbit,1Mbit
+# RATE=28Kbit
+# WEIGHT=2Kbit
+# PRIO=5
+# RULE=192.168.1.1
+# --------------------------------------------------------------------------
+#
+# cbq-128.client-backbone
+# --------------------------------------------------------------------------
+# DEVICE=eth0,10Mbit,1Mbit
+# RATE=128Kbit
+# WEIGHT=10Kbit
+# PRIO=5
+# RULE=192.168.1.1,
+# --------------------------------------------------------------------------
+#
+# Pay attention to comma "," in the RULE field - it denotes source address!
+#
+# Enjoy.
+#
+#############################################################################
+
+export LC_ALL=C
+
+### Command locations
+TC=/sbin/tc
+IP=/sbin/ip
+MP=/sbin/modprobe
+
+### Default filter priorities (must be different)
+PRIO_RULE_DEFAULT=${PRIO_RULE:-100}
+PRIO_MARK_DEFAULT=${PRIO_MARK:-200}
+PRIO_REALM_DEFAULT=${PRIO_REALM:-300}
+
+### Default CBQ_PATH & CBQ_CACHE settings
+CBQ_PATH=${CBQ_PATH:-/etc/sysconfig/cbq}
+CBQ_CACHE=${CBQ_CACHE:-/var/cache/cbq.init}
+
+### Uncomment to enable logfile for debugging
+#CBQ_DEBUG="/var/run/cbq-$1"
+
+### Modules to probe for. Uncomment the last CBQ_PROBE
+### line if you have QoS support compiled into kernel
+CBQ_PROBE="sch_cbq sch_tbf sch_sfq sch_prio"
+CBQ_PROBE="$CBQ_PROBE cls_fw cls_u32 cls_route"
+#CBQ_PROBE=""
+
+### Keywords required for qdisc & class configuration
+CBQ_WORDS="DEVICE|RATE|WEIGHT|PRIO|PARENT|LEAF|BOUNDED|ISOLATED"
+CBQ_WORDS="$CBQ_WORDS|PRIO_MARK|PRIO_RULE|PRIO_REALM|BUFFER"
+CBQ_WORDS="$CBQ_WORDS|LIMIT|PEAK|MTU|QUANTUM|PERTURB"
+
+### Source AVPKT if it exists
+[ -r /etc/sysconfig/cbq/avpkt ] && . /etc/sysconfig/cbq/avpkt
+AVPKT=${AVPKT:-3000}
+
+
+#############################################################################
+############################# SUPPORT FUNCTIONS #############################
+#############################################################################
+
+### Get list of network devices
+cbq_device_list () {
+	ip link show| sed -n "/^[0-9]/ \
+		{ s/^[0-9]\+: \([a-z0-9._]\+\)[:@].*/\1/; p; }"
+} # cbq_device_list
+
+
+### Remove root class from device $1
+cbq_device_off () {
+	tc qdisc del dev $1 root 2> /dev/null
+} # cbq_device_off
+
+
+### Remove CBQ from all devices
+cbq_off () {
+	for dev in `cbq_device_list`; do
+		cbq_device_off $dev
+	done
+} # cbq_off
+
+
+### Prefixed message
+cbq_message () {
+	echo -e "**CBQ: $@"
+} # cbq_message
+
+### Failure message
+cbq_failure () {
+	cbq_message "$@"
+	exit 1
+} # cbq_failure
+
+### Failure w/ cbq-off
+cbq_fail_off () {
+	cbq_message "$@"
+	cbq_off
+	exit 1
+} # cbq_fail_off
+
+
+### Convert time to absolute value
+cbq_time2abs () {
+	local min=${1##*:}; min=${min##0}
+	local hrs=${1%%:*}; hrs=${hrs##0}
+	echo $[hrs*60 + min]
+} # cbq_time2abs
+
+
+### Display CBQ setup
+cbq_show () {
+	for dev in `cbq_device_list`; do
+		[ `tc qdisc show dev $dev| wc -l` -eq 0 ] && continue
+		echo -e "### $dev: queueing disciplines\n"
+		tc $1 qdisc show dev $dev; echo
+
+		[ `tc class show dev $dev| wc -l` -eq 0 ] && continue
+		echo -e "### $dev: traffic classes\n"
+		tc $1 class show dev $dev; echo
+
+		[ `tc filter show dev $dev| wc -l` -eq 0 ] && continue
+		echo -e "### $dev: filtering rules\n"
+		tc $1 filter show dev $dev; echo
+	done
+} # cbq_show
+
+
+### Check configuration and load DEVICES, DEVFIELDS and CLASSLIST from $1
+cbq_init () {
+	### Get a list of configured classes
+	CLASSLIST=`find $1 -maxdepth 1 \( -type f -or -type l \) -name 'cbq-*' \
+		-not -name '*~' -printf "%f\n"| sort`
+	[ -z "$CLASSLIST" ] &&
+		cbq_failure "no configuration files found in $1!"
+
+	### Gather all DEVICE fields from $1/cbq-*
+	DEVFIELDS=`find $1 -maxdepth 1 \( -type f -or -type l \) -name 'cbq-*' \
+		  -not -name '*~' | xargs sed -n 's/#.*//; \
+		  s/[[:space:]]//g; /^DEVICE=[^,]*,[^,]*\(,[^,]*\)\?/ \
+		  { s/.*=//; p; }'| sort -u`
+	[ -z "$DEVFIELDS" ] &&
+		cbq_failure "no DEVICE field found in $1/cbq-*!"
+
+	### Check for different DEVICE fields for the same device
+	DEVICES=`echo "$DEVFIELDS"| sed 's/,.*//'| sort -u`
+	[ `echo "$DEVICES"| wc -l` -ne `echo "$DEVFIELDS"| wc -l` ] &&
+		cbq_failure "different DEVICE fields for single device!\n$DEVFIELDS"
+} # cbq_init
+
+
+### Load class configuration from $1/$2
+cbq_load_class () {
+	CLASS=`echo $2| sed 's/^cbq-0*//; s/^\([0-9a-fA-F]\+\).*/\1/'`
+	CFILE=`sed -n 's/#.*//; s/[[:space:]]//g; /^[[:alnum:]_]\+=[[:alnum:].,:;/*@-_]\+$/ p' $1/$2`
+
+	### Check class number
+	IDVAL=`/usr/bin/printf "%d" 0x$CLASS 2> /dev/null`
+	[ $? -ne 0 -o $IDVAL -lt 2 -o $IDVAL -gt 65535 ] &&
+		cbq_fail_off "class ID of $2 must be in range <0002-FFFF>!"
+
+	### Set defaults & load class
+	RATE=""; WEIGHT=""; PARENT=""; PRIO=5
+	LEAF=tbf; BOUNDED=yes; ISOLATED=no
+	BUFFER=10Kb/8; LIMIT=15Kb; MTU=1500
+	PEAK=""; PERTURB=10; QUANTUM=""
+
+	PRIO_RULE=$PRIO_RULE_DEFAULT
+	PRIO_MARK=$PRIO_MARK_DEFAULT
+	PRIO_REALM=$PRIO_REALM_DEFAULT
+
+	eval `echo "$CFILE"| grep -E "^($CBQ_WORDS)="`
+
+	### Require RATE/WEIGHT
+	[ -z "$RATE" -o -z "$WEIGHT" ] &&
+		cbq_fail_off "missing RATE or WEIGHT in $2!"
+
+	### Class device
+	DEVICE=${DEVICE%%,*}
+	[ -z "$DEVICE" ] && cbq_fail_off "missing DEVICE field in $2!"
+
+	BANDWIDTH=`echo "$DEVFIELDS"| sed -n "/^$DEVICE,/ \
+		  { s/[^,]*,\([^,]*\).*/\1/; p; q; }"`
+
+	### Convert to "tc" options
+	PEAK=${PEAK:+peakrate $PEAK}
+	PERTURB=${PERTURB:+perturb $PERTURB}
+	QUANTUM=${QUANTUM:+quantum $QUANTUM}
+
+	[ "$BOUNDED" = "no" ] && BOUNDED="" || BOUNDED="bounded"
+	[ "$ISOLATED" = "yes" ] && ISOLATED="isolated" || ISOLATED=""
+} # cbq_load_class
+
+
+#############################################################################
+#################################### INIT ###################################
+#############################################################################
+
+### Check for presence of ip-route2 in usual place
+[ -x $TC -a -x $IP ] ||
+	cbq_failure "ip-route2 utilities not installed or executable!"
+
+
+### ip/tc wrappers
+if [ "$1" = "compile" ]; then
+	### no module probing
+	CBQ_PROBE=""
+
+	ip () {
+		$IP "$@"
+	} # ip
+
+	### echo-only version of "tc" command
+	tc () {
+		echo "$TC $@"
+	} # tc
+
+elif [ -n "$CBQ_DEBUG" ]; then
+	echo -e "# `date`" > $CBQ_DEBUG
+
+	### Logging version of "ip" command
+	ip () {
+		echo -e "\n# ip $@" >> $CBQ_DEBUG
+		$IP "$@" 2>&1 | tee -a $CBQ_DEBUG
+	} # ip
+
+	### Logging version of "tc" command
+	tc () {
+		echo -e "\n# tc $@" >> $CBQ_DEBUG
+		$TC "$@" 2>&1 | tee -a $CBQ_DEBUG
+	} # tc
+else
+	### Default wrappers
+	
+	ip () {
+		$IP "$@"
+	} # ip
+	
+	tc () {
+		$TC "$@"
+	} # tc
+fi # ip/tc wrappers
+
+
+case "$1" in
+
+#############################################################################
+############################### START/COMPILE ###############################
+#############################################################################
+
+start|compile)
+
+### Probe QoS modules (start only)
+for module in $CBQ_PROBE; do
+	$MP $module || cbq_failure "failed to load module $module"
+done
+
+### If we are in compile/nocache/logging mode, don't bother with cache
+if [ "$1" != "compile" -a "$2" != "nocache" -a -z "$CBQ_DEBUG" ]; then
+	VALID=1
+
+	### validate the cache
+	[ "$2" = "invalidate" -o ! -f $CBQ_CACHE ] && VALID=0
+	if [ $VALID -eq 1 ]; then
+		[ `find $CBQ_PATH -maxdepth 1 -newer $CBQ_CACHE| \
+		  wc -l` -gt 0 ] && VALID=0
+	fi
+
+	### compile the config if the cache is invalid
+	if [ $VALID -ne 1 ]; then
+		$0 compile > $CBQ_CACHE ||
+			cbq_fail_off "failed to compile CBQ configuration!"
+	fi
+
+	### run the cached commands
+	exec /bin/sh $CBQ_CACHE 2> /dev/null
+fi
+
+### Load DEVICES, DEVFIELDS and CLASSLIST
+cbq_init $CBQ_PATH
+
+
+### Setup root qdisc on all configured devices
+for dev in $DEVICES; do
+	### Retrieve device bandwidth and, optionally, weight
+	DEVTEMP=`echo "$DEVFIELDS"| sed -n "/^$dev,/ { s/$dev,//; p; q; }"`
+	DEVBWDT=${DEVTEMP%%,*};	DEVWGHT=${DEVTEMP##*,}
+	[ "$DEVBWDT" = "$DEVWGHT" ] && DEVWGHT=""
+
+	### Device bandwidth is required
+	if [ -z "$DEVBWDT" ]; then
+		cbq_message "could not determine bandwidth for device $dev!"
+		cbq_failure "please set up the DEVICE fields properly!"
+	fi
+
+	### Check if the device is there
+	ip link show $dev &> /dev/null ||
+		cbq_fail_off "device $dev not found!"
+
+	### Remove old root qdisc from device
+	cbq_device_off $dev
+
+
+	### Setup root qdisc + class for device
+	tc qdisc add dev $dev root handle 1 cbq \
+	bandwidth $DEVBWDT avpkt $AVPKT cell 8
+
+	### Set weight of the root class if set
+	[ -n "$DEVWGHT" ] &&
+		tc class change dev $dev root cbq weight $DEVWGHT allot 1514
+
+	[ "$1" = "compile" ] && echo
+done # dev
+
+
+### Setup traffic classes
+for classfile in $CLASSLIST; do
+	cbq_load_class $CBQ_PATH $classfile
+
+	### Create the class
+	tc class add dev $DEVICE parent 1:$PARENT classid 1:$CLASS cbq \
+	bandwidth $BANDWIDTH rate $RATE weight $WEIGHT prio $PRIO \
+	allot 1514 cell 8 maxburst 20 avpkt $AVPKT $BOUNDED $ISOLATED ||
+		cbq_fail_off "failed to add class $CLASS with parent $PARENT on $DEVICE!"
+
+	### Create leaf qdisc if set
+	if [ "$LEAF" = "tbf" ]; then
+		tc qdisc add dev $DEVICE parent 1:$CLASS handle $CLASS tbf \
+		rate $RATE buffer $BUFFER limit $LIMIT mtu $MTU $PEAK
+	elif [ "$LEAF" = "sfq" ]; then
+		tc qdisc add dev $DEVICE parent 1:$CLASS handle $CLASS sfq \
+		$PERTURB $QUANTUM
+	fi
+
+
+	### Create fw filter for MARK fields
+	for mark in `echo "$CFILE"| sed -n '/^MARK/ { s/.*=//; p; }'`; do
+		### Attach fw filter to root class
+		tc filter add dev $DEVICE parent 1:0 protocol ip \
+		prio $PRIO_MARK handle $mark fw classid 1:$CLASS
+	done ### mark
+
+	### Create route filter for REALM fields
+	for realm in `echo "$CFILE"| sed -n '/^REALM/ { s/.*=//; p; }'`; do
+		### Split realm into source & destination realms
+		SREALM=${realm%%,*}; DREALM=${realm##*,}
+		[ "$SREALM" = "$DREALM" ] && SREALM=""
+
+		### Convert asterisks to empty strings
+		SREALM=${SREALM#\*}; DREALM=${DREALM#\*}
+
+		### Attach route filter to the root class
+		tc filter add dev $DEVICE parent 1:0 protocol ip \
+		prio $PRIO_REALM route ${SREALM:+from $SREALM} \
+		${DREALM:+to $DREALM} classid 1:$CLASS
+	done ### realm
+
+	### Create u32 filter for RULE fields
+	for rule in `echo "$CFILE"| sed -n '/^RULE/ { s/.*=//; p; }'`; do
+		### Split rule into source & destination
+		SRC=${rule%%,*}; DST=${rule##*,}
+		[ "$SRC" = "$rule" ] && SRC=""
+
+
+		### Split destination into address, port & mask fields
+		DADDR=${DST%%:*}; DTEMP=${DST##*:}
+		[ "$DADDR" = "$DST" ] && DTEMP=""
+
+		DPORT=${DTEMP%%/*}; DMASK=${DTEMP##*/}
+		[ "$DPORT" = "$DTEMP" ] && DMASK="0xffff"
+
+
+		### Split up source (if specified)
+		SADDR=""; SPORT=""
+		if [ -n "$SRC" ]; then
+			SADDR=${SRC%%:*}; STEMP=${SRC##*:}
+			[ "$SADDR" = "$SRC" ] && STEMP=""
+
+			SPORT=${STEMP%%/*}; SMASK=${STEMP##*/}
+			[ "$SPORT" = "$STEMP" ] && SMASK="0xffff"
+		fi
+
+
+		### Convert asterisks to empty strings
+		SADDR=${SADDR#\*}; DADDR=${DADDR#\*}
+
+		### Compose u32 filter rules
+		u32_s="${SPORT:+match ip sport $SPORT $SMASK}"
+		u32_s="${SADDR:+match ip src $SADDR} $u32_s"
+		u32_d="${DPORT:+match ip dport $DPORT $DMASK}"
+		u32_d="${DADDR:+match ip dst $DADDR} $u32_d"
+
+		### Uncomment the following if you want to see parsed rules
+		#echo "$rule: $u32_s $u32_d"
+
+		### Attach u32 filter to the appropriate class
+		tc filter add dev $DEVICE parent 1:0 protocol ip \
+		prio $PRIO_RULE u32 $u32_s $u32_d classid 1:$CLASS
+	done ### rule
+
+	[ "$1" = "compile" ] && echo
+done ### classfile
+;;
+
+
+#############################################################################
+################################# TIME CHECK ################################
+#############################################################################
+
+timecheck)
+
+### Get time + weekday
+TIME_TMP=`date +%w/%k:%M`
+TIME_DOW=${TIME_TMP%%/*}
+TIME_NOW=${TIME_TMP##*/}
+
+### Load DEVICES, DEVFIELDS and CLASSLIST
+cbq_init $CBQ_PATH
+
+### Run through all classes
+for classfile in $CLASSLIST; do
+	### Gather all TIME rules from class config
+	TIMESET=`sed -n 's/#.*//; s/[[:space:]]//g; /^TIME/ { s/.*=//; p; }' \
+		$CBQ_PATH/$classfile`
+	[ -z "$TIMESET" ] && continue
+
+	MATCH=0; CHANGE=0
+	for timerule in $TIMESET; do
+		TIME_ABS=`cbq_time2abs $TIME_NOW`
+		
+		### Split TIME rule to pieces
+		TIMESPEC=${timerule%%;*}; PARAMS=${timerule##*;}
+		WEEKDAYS=${TIMESPEC%%/*}; INTERVAL=${TIMESPEC##*/}
+		BEG_TIME=${INTERVAL%%-*}; END_TIME=${INTERVAL##*-}
+
+		### Check the day-of-week (if present)
+		[ "$WEEKDAYS" != "$INTERVAL" -a \
+		  -n "${WEEKDAYS##*$TIME_DOW*}" ] && continue
+
+		### Compute interval boundaries
+		BEG_ABS=`cbq_time2abs $BEG_TIME`
+		END_ABS=`cbq_time2abs $END_TIME`
+
+		### Midnight wrap fixup
+		if [ $BEG_ABS -gt $END_ABS ]; then
+			[ $TIME_ABS -le $END_ABS ] &&
+				TIME_ABS=$[TIME_ABS + 24*60]
+
+			END_ABS=$[END_ABS + 24*60]
+		fi
+
+		### If the time matches, remember params and set MATCH flag
+		if [ $TIME_ABS -ge $BEG_ABS -a $TIME_ABS -lt $END_ABS ]; then
+			TMP_RATE=${PARAMS%%/*}; PARAMS=${PARAMS#*/}
+			TMP_WGHT=${PARAMS%%/*}; TMP_PEAK=${PARAMS##*/}
+
+			[ "$TMP_PEAK" = "$TMP_WGHT" ] && TMP_PEAK=""
+			TMP_PEAK=${TMP_PEAK:+peakrate $TMP_PEAK}
+
+			MATCH=1
+		fi
+	done ### timerule
+
+
+	cbq_load_class $CBQ_PATH $classfile
+
+	### Get current RATE of CBQ class
+	RATE_NOW=`tc class show dev $DEVICE| sed -n \
+		 "/cbq 1:$CLASS / { s/.*rate //; s/ .*//; p; q; }"`
+	[ -z "$RATE_NOW" ] && continue
+
+	### Time interval matched
+	if [ $MATCH -ne 0 ]; then
+
+		### Check if there is any change in class RATE
+		if [ "$RATE_NOW" != "$TMP_RATE" ]; then
+			NEW_RATE="$TMP_RATE"
+			NEW_WGHT="$TMP_WGHT"
+			NEW_PEAK="$TMP_PEAK"
+			CHANGE=1
+		fi
+
+	### Match not found, reset to default RATE if necessary
+	elif [ "$RATE_NOW" != "$RATE" ]; then
+		NEW_WGHT="$WEIGHT"
+		NEW_RATE="$RATE"
+		NEW_PEAK="$PEAK"
+		CHANGE=1
+	fi
+
+	### If there are no changes, go for next class
+	[ $CHANGE -eq 0 ] && continue
+
+	### Replace CBQ class
+	tc class replace dev $DEVICE classid 1:$CLASS cbq \
+	bandwidth $BANDWIDTH rate $NEW_RATE weight $NEW_WGHT prio $PRIO \
+	allot 1514 cell 8 maxburst 20 avpkt $AVPKT $BOUNDED $ISOLATED
+
+	### Replace leaf qdisc (if any)
+	if [ "$LEAF" = "tbf" ]; then
+		tc qdisc replace dev $DEVICE handle $CLASS tbf \
+		rate $NEW_RATE buffer $BUFFER limit $LIMIT mtu $MTU $NEW_PEAK
+	fi
+
+	cbq_message "$TIME_NOW: class $CLASS on $DEVICE changed rate ($RATE_NOW -> $NEW_RATE)"
+done ### class file
+;;
+
+
+#############################################################################
+################################## THE REST #################################
+#############################################################################
+
+stop)
+	cbq_off
+	;;
+
+list)
+	cbq_show
+	;;
+
+stats)
+	cbq_show -s
+	;;
+
+restart)
+	shift
+	$0 stop
+	$0 start "$@"
+	;;
+
+*)
+	echo "Usage: `basename $0` {start|compile|stop|restart|timecheck|list|stats}"
+esac
diff --git a/iproute2/examples/cbqinit.eth1 b/iproute2/examples/cbqinit.eth1
new file mode 100644
index 0000000..226ec1c
--- /dev/null
+++ b/iproute2/examples/cbqinit.eth1
@@ -0,0 +1,76 @@
+#! /bin/sh
+
+TC=/home/root/tc
+IP=/home/root/ip
+DEVICE=eth1
+BANDWIDTH="bandwidth 10Mbit"
+
+# Attach CBQ on $DEVICE. It will have handle 1:.
+#   $BANDWIDTH is real $DEVICE bandwidth (10Mbit).
+#   avpkt is average packet size.
+#   mpu is minimal packet size.
+
+$TC qdisc add dev $DEVICE  root  handle 1:  cbq \
+$BANDWIDTH avpkt 1000 mpu 64
+
+# Create root class with classid 1:1. This step is not necessary.
+#   bandwidth is the same as on CBQ itself.
+#   rate == all the bandwidth
+#   allot is MTU + MAC header
+#   maxburst measure allowed class burstiness (please,read S.Floyd and VJ papers)
+#   est 1sec 8sec means, that kernel will evaluate average rate
+#                 on this class with period 1sec and time constant 8sec.
+#                 This rate is viewed with "tc -s class ls dev $DEVICE"
+
+$TC class add dev $DEVICE parent 1:0 classid :1 est 1sec 8sec cbq \
+$BANDWIDTH rate 10Mbit allot 1514 maxburst 50 avpkt 1000
+
+# Bulk.
+#    New parameters are: 
+#    weight, which is set to be proportional to
+#            "rate". It is not necessary, weight=1 will work as well.
+#    defmap and split say that best effort ttraffic, not classfied
+#            by another means will fall to this class.
+
+$TC class add dev $DEVICE parent 1:1 classid :2 est 1sec 8sec cbq \
+$BANDWIDTH rate 4Mbit allot 1514 weight 500Kbit \
+prio 6 maxburst 50 avpkt 1000 split 1:0 defmap ff3d
+
+# OPTIONAL.
+# Attach "sfq" qdisc to this class, quantum is MTU, perturb
+# gives period of hash function perturbation in seconds.
+#
+$TC qdisc add dev $DEVICE parent 1:2 sfq quantum 1514b perturb 15
+
+# Interactive-burst class
+
+$TC class add dev $DEVICE parent 1:1 classid :3 est 2sec 16sec cbq \
+$BANDWIDTH rate 1Mbit allot 1514 weight 100Kbit \
+prio 2 maxburst 100 avpkt 1000 split 1:0 defmap c0
+
+$TC qdisc add dev $DEVICE parent 1:3 sfq quantum 1514b perturb 15
+
+# Background.
+
+$TC class add dev $DEVICE parent 1:1 classid :4 est 1sec 8sec cbq \
+  $BANDWIDTH rate 100Kbit allot 1514 weight 10Mbit \
+  prio 7 maxburst 10 avpkt 1000 split 1:0 defmap 2
+
+$TC qdisc add dev $DEVICE parent 1:4 sfq quantum 1514b perturb 15
+
+# Realtime class for RSVP
+
+$TC class add dev $DEVICE parent 1:1 classid 1:7FFE cbq \
+rate 5Mbit $BANDWIDTH allot 1514b avpkt 1000 \
+maxburst 20
+
+# Reclassified realtime traffic
+#
+# New element: split is not 1:0, but 1:7FFE. It means,
+#     that only real-time packets, which violated policing filters
+#     or exceeded reshaping buffers will fall to it.
+
+$TC class add dev $DEVICE parent 1:7FFE classid 1:7FFF  est 4sec 32sec cbq \
+rate 1Mbit $BANDWIDTH allot 1514b avpkt 1000 weight 10Kbit \
+prio 6 maxburst 10 split 1:7FFE defmap ffff
+
diff --git a/iproute2/examples/dhcp-client-script b/iproute2/examples/dhcp-client-script
new file mode 100644
index 0000000..f39bc10
--- /dev/null
+++ b/iproute2/examples/dhcp-client-script
@@ -0,0 +1,446 @@
+#!/bin/bash
+#
+# dhclient-script for Linux.
+#
+#		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.
+#
+# Authors:	Alexey Kuznetsov, <kuznet@ms2.inr.ac.ru>
+#
+# Probably, I did not understand, what this funny feature as "alias"
+# means exactly. For now I suppose, that it is a static address, which
+# we should install and preserve.
+#
+
+exec >> /var/log/DHS.log 2>&1
+
+echo dhc-script $* reason=$reason
+set | grep "^\(old_\|new_\|check_\)"
+
+LOG () {
+    echo LOG $* ;
+}
+
+# convert 8bit mask to length
+# arg: $1 = mask
+#
+Mask8ToLen() {
+	local l=0;
+
+	while [ $l -le 7 ]; do
+		if [ $[ ( 1 << $l ) + $1 ] -eq 256 ]; then
+			return	$[ 8 - $l ]
+		fi
+		l=$[ $l + 1 ]
+	done
+	return 0;
+}
+
+# convert inet dotted quad mask to length
+# arg: $1 = dotquad mask
+#
+MaskToLen() {
+ local masklen=0
+ local mask8=$1
+
+ case $1 in
+ 0.0.0.0)
+	return 0;
+	;;
+ 255.*.0.0)
+	masklen=8
+	mask8=${mask8#255.}
+	mask8=${mask8%.0.0}
+	;;
+ 255.255.*.0)
+	masklen=16
+	mask8=${mask8#255.255.}
+	mask8=${mask8%.0}
+	;;
+ 255.255.255.*)
+	masklen=24
+	mask8=${mask8#255.255.255.}
+	;;
+ *)
+	return 255
+	;;
+ esac
+ Mask8ToLen $mask8
+ return $[ $? + $masklen ]
+}
+
+# calculate ABC "natural" mask
+# arg: $1 = dotquad address
+#
+ABCMask () {
+ local class;
+
+ class=${1%%.*}
+
+ if [ "$1" = "255.255.255.255" ]; then
+    echo $1
+ elif [ "$1" = "0.0.0.0" ]; then
+    echo $1
+ elif [ $class -ge 224 ]; then
+    echo 240.0.0.0
+ elif [ $class -ge 192 ]; then
+    echo 255.255.255.0
+ elif [ $class -ge 128 ]; then
+    echo 255.255.0.0
+ else
+    echo 255.0.0.0
+ fi
+}
+
+# calculate ABC "natural" mask length
+# arg: $1 = dotquad address
+#
+ABCMaskLen () {
+ local class;
+
+ class=${1%%.*}
+
+ if [ "$1" = "255.255.255.255" ]; then
+    return 32
+ elif [ "$1" = "0.0.0.0" ]; then
+    return 0
+ elif [ $class -ge 224 ]; then
+    return 4;
+ elif [ $class -ge 192 ]; then
+    return 24;
+ elif [ $class -ge 128 ]; then
+    return 16;
+ else
+    return 8;
+ fi
+}
+
+# Delete IP address
+# args: $1 = interface
+#       $2 = address
+#       $3 = mask
+#       $4 = broadcast
+#       $5 = label
+#
+DelINETAddr () {
+  local masklen=32
+  local addrid=$1
+
+  LOG DelINETAddr $*
+
+  if [ "$5" ]; then
+    addrid=$addrid:$5
+  fi
+  LOG ifconfig $addrid down
+  ifconfig $addrid down
+}
+
+# Add IP address
+# args: $1 = interface
+#       $2 = address
+#       $3 = mask
+#       $4 = broadcast
+#       $5 = label
+#
+AddINETAddr () {
+  local mask_arg
+  local brd_arg
+  local addrid=$1
+
+  LOG AddINETAddr $*
+
+  if [ "$5" ]; then
+    addrid=$addrid:$5
+  fi
+  if [ "$3" ]; then
+    mask_arg="netmask $3"
+  fi
+  if [ "$4" ]; then
+    brd_arg="broadcast $4"
+  fi
+
+  LOG ifconfig $addrid $2 $mask_arg $brd_arg up
+  ifconfig $addrid $2 $mask_arg $brd_arg up
+}
+
+# Add default routes
+# args: $1 = routers list
+#
+AddDefaultRoutes() {
+    local router
+
+    if [ "$1" ]; then
+      LOG AddDefaultRoutes $*
+      for router in $1; do
+        LOG route add default gw $router
+        route add default gw $router
+      done ;
+    fi
+}
+
+# Delete default routes
+# args: $1 = routers list
+#
+DelDefaultRoutes() {
+    local router
+
+    if [ "$1" ]; then
+      LOG DelDefaultRoutes $*
+
+      for router in $1; do
+        LOG route del default gw $router
+        route del default gw $router
+      done
+    fi
+}
+
+# ping a host
+# args: $1 = dotquad address of the host
+#
+PingNode() {
+    LOG PingNode $*
+    if ping -q -c 1 -w 2 $1 ; then
+	return 0;
+    fi
+    return 1;
+}
+
+# Check (and add route, if alive) default routers
+# args: $1 = routers list
+# returns: 0 if at least one router is alive.
+#
+CheckRouterList() {
+    local router
+    local succeed=1
+
+    LOG CheckRouterList $*
+
+    for router in $1; do
+      if PingNode $router ; then
+	succeed=0
+        route add default gw $router
+      fi
+    done
+    return $succeed
+}
+
+# Delete/create static routes.
+# args: $1 = operation (del/add)
+#       $2 = routes list in format "dst1 nexthop1 dst2 ..."
+#
+# BEWARE: this feature of DHCP is obsolete, because does not
+#         support subnetting.
+#
+X-StaticRouteList() {
+    local op=$1
+    local lst="$2"
+    local masklen
+
+    LOG X-StaticRouteList $*
+
+    if [ "$lst" ]; then
+      set $lst
+      while [ $# -gt 1 ]; do
+	route $op -net $1 netmask `ABCMask "$1"` gw $2
+	shift; shift;
+      done
+   fi
+}
+
+# Create static routes.
+# arg: $1 = routes list in format "dst1 nexthop1 dst2 ..."
+#
+AddStaticRouteList() {
+    LOG AddStaticRouteList $*
+    X-StaticRouteList add "$1"
+}
+
+# Delete static routes.
+# arg: $1 = routes list in format "dst1 nexthop1 dst2 ..."
+#
+DelStaticRouteList() {
+    LOG DelStaticRouteList $*
+    X-StaticRouteList del "$1"
+}
+
+# Broadcast unsolicited ARP to update neighbours' caches.
+# args: $1 = interface
+#       $2 = address
+#
+UnsolicitedARP() {
+    if [ -f /sbin/arping ]; then
+	/sbin/arping -A -c 1 -I "$1" "$2" &
+	(sleep 2 ; /sbin/arping -U -c 1 -I "$1" "$2" ) &
+    fi
+}
+
+# Duplicate address detection.
+# args: $1 = interface
+#       $2 = test address
+# returns: 0, if DAD succeeded.
+DAD() {
+  if [ -f /sbin/arping ]; then
+	/sbin/arping -c 2 -w 3 -D -I "$1" "$2"
+	return $?
+  fi
+  return 0
+}
+
+
+# Setup resolver.
+# args: NO
+#       domain and nameserver list are passed in global variables.
+#
+# NOTE: we try to be careful and not to break user supplied resolv.conf.
+#       The script mangles it, only if it has dhcp magic signature.
+#
+UpdateDNS() {
+    local nameserver
+    local idstring="#### Generated by DHCPCD"
+
+    LOG UpdateDNS $*
+
+    if [ "$new_domain_name" = "" -a "$new_domain_name_servers" = "" ]; then
+	return 0;
+    fi
+
+    echo $idstring > /etc/resolv.conf.dhcp
+    if [ "$new_domain_name" ]; then
+	echo search $new_domain_name >> /etc/resolv.conf.dhcp
+    fi
+    echo options ndots:1 >> /etc/resolv.conf.dhcp
+
+    if [ "$new_domain_name_servers" ]; then
+	for nameserver in $new_domain_name_servers; do
+	    echo nameserver $nameserver >> /etc/resolv.conf.dhcp
+	done
+    else
+	echo nameserver 127.0.0.1 >> /etc/resolv.conf.dhcp
+    fi
+
+    if [ -f /etc/resolv.conf ]; then
+	if [ "`head -1 /etc/resolv.conf`" != "$idstring" ]; then
+	    return 0
+	fi
+	if [ "$old_domain_name" = "$new_domain_name" -a
+	     "$new_domain_name_servers" = "$old_domain_name_servers" ]; then
+	     return 0
+	fi
+    fi
+    mv /etc/resolv.conf.dhcp /etc/resolv.conf
+}
+
+case $reason in
+NBI)
+  exit 1
+  ;;
+
+MEDIUM)
+  exit 0
+  ;;
+
+PREINIT)
+  ifconfig $interface:dhcp down
+  ifconfig $interface:dhcp1 down
+  if [ -d /proc/sys/net/ipv4/conf/$interface ]; then
+    ifconfig $interface:dhcp 10.10.10.10 netmask 255.255.255.255
+    ifconfig $interface:dhcp down
+    if [ -d /proc/sys/net/ipv4/conf/$interface ]; then
+	LOG The interface $interface already configured.
+    fi
+  fi
+  ifconfig $interface:dhcp up
+  exit 0
+  ;;
+
+ARPSEND)
+  exit 0
+  ;;
+
+ARPCHECK)
+  if DAD "$interface" "$check_ip_address" ; then
+    exit 0
+  fi
+  exit 1
+  ;;
+
+BOUND|RENEW|REBIND|REBOOT)
+  if [ "$old_ip_address" -a "$alias_ip_address" -a \
+	"$alias_ip_address" != "$old_ip_address" ]; then
+    DelINETAddr "$interface" "$alias_ip_address" "$alias_subnet_mask" "$alias_broadcast_address" dhcp1
+  fi
+  if [ "$old_ip_address" -a "$old_ip_address" != "$new_ip_address" ]; then
+    DelINETAddr "$interface" "$old_ip_address" "$old_subnet_mask" "$old_broadcast_address" dhcp
+    DelDefaultRoutes "$old_routers"
+    DelStaticRouteList "$old_static_routes"
+  fi
+  if [ "$old_ip_address" = "" -o "$old_ip_address" != "$new_ip_address" -o \
+       "$reason" = "BOUND" -o "$reason" = "REBOOT" ]; then
+    AddINETAddr "$interface" "$new_ip_address" "$new_subnet_mask" "$new_broadcast_address" dhcp
+    AddStaticRouteList "$new_static_routes"
+    AddDefaultRoutes "$new_routers"
+    UnsolicitedARP "$interface" "$new_ip_address"
+  fi
+  if [ "$new_ip_address" != "$alias_ip_address" -a "$alias_ip_address" ]; then
+    AddINETAddr "$interface" "$alias_ip_address" "$alias_subnet_mask" "$alias_broadcast_address" dhcp1
+  fi
+  UpdateDNS
+  exit 0
+  ;;
+
+EXPIRE|FAIL)
+  if [ "$alias_ip_address" ]; then
+    DelINETAddr "$interface" "$alias_ip_address" "$alias_subnet_mask" "$alias_broadcast_address" dhcp1
+  fi
+  if [ "$old_ip_address" ]; then
+    DelINETAddr "$interface" "$old_ip_address" "$old_subnet_mask" "$old_broadcast_address" dhcp
+    DelDefaultRoutes "$old_routers"
+    DelStaticRouteList "$old_static_routes"
+  fi
+  if [ "$alias_ip_address" ]; then
+    AddINETAddr "$interface" "$alias_ip_address" "$alias_subnet_mask" "$alias_broadcast_address" dhcp1
+  fi
+  exit 0
+  ;;
+
+TIMEOUT)
+  if [ "$alias_ip_address" ]; then
+    DelINETAddr "$interface" "$alias_ip_address" "$alias_subnet_mask" "$alias_broadcast_address" dhcp1
+  fi
+# Seems, <null address> means, that no more old leases found.
+# Or does it mean bug in dhcpcd? 8) Fail for now.
+  if [ "$new_ip_address" = "<null address>" ]; then
+    if [ "$old_ip_address" ]; then
+	DelINETAddr "$interface" "$old_ip_address" "$old_subnet_mask" "$old_broadcast_address" dhcp
+    fi
+    if [ "$alias_ip_address" ]; then
+        AddINETAddr "$interface" "$alias_ip_address" "$alias_subnet_mask" "$alias_broadcast_address" dhcp1
+    fi
+    exit 1
+  fi
+  if DAD "$interface" "$new_ip_address" ; then
+    AddINETAddr "$interface" "$new_ip_address" "$new_subnet_mask" "$new_broadcast_address" dhcp
+    UnsolicitedARP "$interface" "$new_ip_address"
+    if [ "$alias_ip_address" -a "$alias_ip_address" != "$new_ip_address" ]; then
+      AddINETAddr "$interface" "$alias_ip_address" "$alias_subnet_mask" "$alias_broadcast_address" dhcp1
+      UnsolicitedARP "$interface" "$alias_ip_address"
+    fi
+    if CheckRouterList "$new_routers" ; then
+	AddStaticRouteList "$new_static_routes"
+	UpdateDNS
+	exit 0
+    fi
+  fi
+  DelINETAddr "$interface" "$new_ip_address" "$new_subnet_mask" "$new_broadcast_address" dhcp
+  DelDefaultRoutes "$old_routers"
+  DelStaticRouteList "$old_static_routes"
+  if [ "$alias_ip_address" ]; then
+    AddINETAddr "$interface" "$alias_ip_address" "$alias_subnet_mask" "$alias_broadcast_address" dhcp1
+  fi
+  exit 1
+  ;;
+esac
+
+exit 0
diff --git a/iproute2/examples/diffserv/Edge1 b/iproute2/examples/diffserv/Edge1
new file mode 100644
index 0000000..4ddffdd
--- /dev/null
+++ b/iproute2/examples/diffserv/Edge1
@@ -0,0 +1,68 @@
+#! /bin/sh -x
+#
+# sample script on using the ingress capabilities
+# This script just tags on the ingress interfac using Ipchains
+# the result is used for fast classification and re-marking
+# on the egress interface
+#
+#path to various utilities;
+#change to reflect yours.
+#
+IPROUTE=/root/DS-6-beta/iproute2-990530-dsing
+TC=$IPROUTE/tc/tc
+IP=$IPROUTE/ip/ip
+IPCHAINS=/root/DS-6-beta/ipchains-1.3.9/ipchains
+INDEV=eth2
+EGDEV="dev eth1"
+#
+# tag all incoming packets from host 10.2.0.24 to value 1
+# tag all incoming packets from host 10.2.0.3 to value 2
+# tag the rest of incoming packets from subnet 10.2.0.0/24 to value 3
+#These values are used in the egress
+#
+############################################################ 
+$IPCHAINS -A input -s 10.2.0.4/24 -m 3
+$IPCHAINS -A input -i $INDEV -s 10.2.0.24 -m 1
+$IPCHAINS -A input -i $INDEV -s 10.2.0.3 -m 2
+
+######################## Egress side ########################
+
+
+# attach a dsmarker
+#
+$TC qdisc add $EGDEV handle 1:0 root dsmark indices 64 set_tc_index
+#
+# values of the DSCP to change depending on the class
+#
+#becomes EF
+$TC class change $EGDEV classid 1:1 dsmark mask 0x3 \
+       value 0xb8
+#becomes AF11
+$TC class change $EGDEV classid 1:2 dsmark mask 0x3 \
+       value 0x28
+#becomes AF21
+$TC class change $EGDEV classid 1:3 dsmark mask 0x3 \
+       value 0x48
+#
+#
+# The class mapping
+#
+$TC filter add $EGDEV parent 1:0 protocol ip prio 4 handle 1 fw classid 1:1
+$TC filter add $EGDEV parent 1:0 protocol ip prio 4 handle 2 fw classid 1:2
+$TC filter add $EGDEV parent 1:0 protocol ip prio 4 handle 3 fw classid 1:3
+#
+
+#
+echo "---- qdisc parameters Ingress  ----------"
+$TC qdisc ls dev $INDEV
+echo "---- Class parameters Ingress  ----------"
+$TC class ls dev $INDEV
+echo "---- filter parameters Ingress ----------"
+$TC filter ls dev $INDEV parent 1:0
+
+echo "---- qdisc parameters Egress  ----------"
+$TC qdisc ls $EGDEV
+echo "---- Class parameters Egress  ----------"
+$TC class ls $EGDEV
+echo "---- filter parameters Egress ----------"
+$TC filter ls $EGDEV parent 1:0
diff --git a/iproute2/examples/diffserv/Edge2 b/iproute2/examples/diffserv/Edge2
new file mode 100644
index 0000000..2f78da2
--- /dev/null
+++ b/iproute2/examples/diffserv/Edge2
@@ -0,0 +1,87 @@
+#! /bin/sh -x
+#
+# sample script on using the ingress capabilities
+# This script tags the fwmark on the ingress interface using IPchains
+# the result is used first for policing on the Ingress interface then
+# for fast classification and re-marking
+# on the egress interface
+#
+#path to various utilities;
+#change to reflect yours.
+#
+IPROUTE=/root/DS-6-beta/iproute2-990530-dsing
+TC=$IPROUTE/tc/tc
+IP=$IPROUTE/ip/ip
+IPCHAINS=/root/DS-6-beta/ipchains-1.3.9/ipchains
+INDEV=eth2
+EGDEV="dev eth1"
+#
+# tag all incoming packets from host 10.2.0.24 to value 1
+# tag all incoming packets from host 10.2.0.3 to value 2
+# tag the rest of incoming packets from subnet 10.2.0.0/24 to value 3
+#These values are used in the egress
+############################################################ 
+$IPCHAINS -A input -s 10.2.0.0/24 -m 3
+$IPCHAINS -A input -i $INDEV -s 10.2.0.24 -m 1
+$IPCHAINS -A input -i $INDEV -s 10.2.0.3 -m 2
+############################################################ 
+#
+# install the ingress qdisc on the ingress interface
+############################################################ 
+$TC qdisc add dev $INDEV handle ffff: ingress
+############################################################ 
+
+#
+# attach a fw classifier to the ingress which polices anything marked
+# by ipchains to tag value 3 (The rest of the subnet packets -- not
+# tag 1 or 2) to not go beyond 1.5Mbps
+# Allow up to at least 60 packets to burst (assuming maximum packet 
+# size of # 1.5 KB) in the long run and upto about 6 packets in the
+# shot run
+
+############################################################ 
+$TC filter add dev $INDEV parent ffff: protocol ip prio 50 handle 3 fw \
+police rate 1500kbit burst 90k mtu 9k drop flowid :1
+############################################################ 
+
+######################## Egress side ########################
+
+
+# attach a dsmarker
+#
+$TC qdisc add $EGDEV handle 1:0 root dsmark indices 64
+#
+# values of the DSCP to change depending on the class
+#
+$TC class change $EGDEV classid 1:1 dsmark mask 0x3 \
+       value 0xb8
+$TC class change $EGDEV classid 1:2 dsmark mask 0x3 \
+       value 0x28
+$TC class change $EGDEV classid 1:3 dsmark mask 0x3 \
+       value 0x48
+#
+#
+# The class mapping
+#
+$TC filter add $EGDEV parent 1:0 protocol ip prio 4 handle 1 fw classid 1:1
+$TC filter add $EGDEV parent 1:0 protocol ip prio 4 handle 2 fw classid 1:2
+$TC filter add $EGDEV parent 1:0 protocol ip prio 4 handle 3 fw classid 1:3
+#
+
+#
+echo "---- qdisc parameters Ingress  ----------"
+$TC qdisc ls dev $INDEV
+echo "---- Class parameters Ingress  ----------"
+$TC class ls dev $INDEV
+echo "---- filter parameters Ingress ----------"
+$TC filter ls dev $INDEV parent ffff:
+
+echo "---- qdisc parameters Egress  ----------"
+$TC qdisc ls $EGDEV
+echo "---- Class parameters Egress  ----------"
+$TC class ls $EGDEV
+echo "---- filter parameters Egress ----------"
+$TC filter ls $EGDEV parent 1:0
+#
+#deleting the ingress qdisc
+#$TC qdisc del $DEV ingress
diff --git a/iproute2/examples/diffserv/Edge31-ca-u32 b/iproute2/examples/diffserv/Edge31-ca-u32
new file mode 100644
index 0000000..25e6c0b
--- /dev/null
+++ b/iproute2/examples/diffserv/Edge31-ca-u32
@@ -0,0 +1,170 @@
+#! /bin/sh -x
+#
+# sample script on using the ingress capabilities using u32 classifier
+# This script tags tcindex based on metering on the ingress 
+# interface the result is used for fast classification and re-marking
+# on the egress interface
+# This is an example of a color aware mode marker with PIR configured
+# based on draft-wahjak-mcm-00.txt (section 3.1)
+#
+# The colors are defined using the Diffserv Fields
+#path to various utilities;
+#change to reflect yours.
+#
+IPROUTE=/usr/src/iproute2-current
+TC=$IPROUTE/tc/tc
+IP=$IPROUTE/ip/ip
+INDEV=eth0
+EGDEV="dev eth1"
+CIR1=1500kbit
+CIR2=1000kbit
+
+#The CBS is about 60 MTU sized packets
+CBS1=90k
+CBS2=90k
+
+############################################################ 
+#
+# install the ingress qdisc on the ingress interface
+$TC qdisc add dev $INDEV handle ffff: ingress
+############################################################ 
+#
+# Create u32 filters 
+$TC filter add dev $INDEV parent ffff: protocol ip prio 4 handle 1: u32 \
+divisor 1
+############################################################ 
+
+# The meters: Note that we have shared meters in this case as identified
+# by the index parameter
+meter1=" police index 1 rate $CIR1 burst $CBS1 "
+meter2=" police index 2 rate $CIR2 burst $CBS1 "
+meter3=" police index 3 rate $CIR2 burst $CBS2 "
+meter4=" police index 4 rate $CIR1 burst $CBS2 "
+meter5=" police index 5 rate $CIR1 burst $CBS2 "
+
+# All packets are marked with a tcindex value which is used on the egress
+# tcindex 1 maps to AF41, 2->AF42, 3->AF43, 4->BE
+
+# *********************** AF41 *************************** 
+#AF41 (DSCP 0x22) is passed on with a tcindex value 1
+#if it doesnt exceed its CIR/CBS 
+#policer 1  is used.
+#
+$TC filter add dev $INDEV parent ffff: protocol ip prio 4 u32 \
+match ip tos 0x88 0xfc \
+$meter1 \
+continue flowid :1
+#
+# if it exceeds the above but not the extra rate/burst below, it gets a 
+# tcindex value  of 2
+# policer 2 is used
+#
+$TC filter add dev $INDEV parent ffff: protocol ip prio 5 u32 \
+match ip tos 0x88 0xfc \
+$meter2 \
+continue flowid :2
+#
+# if it exceeds the above but not the rule below, it gets a tcindex value
+# of 3 (policer 3)
+#
+$TC filter add dev $INDEV parent ffff: protocol ip prio 6 u32 \
+match ip tos 0x88 0xfc \
+$meter3 \
+drop flowid :3
+#
+
+# *********************** AF42 *************************** 
+#AF42 (DSCP 0x24) from is passed on with a tcindex value 2
+#if it doesnt exceed its CIR/CBS 
+#policer 2 is used. Note that this is shared with the AF41
+#
+#
+$TC filter add dev $INDEV parent ffff: protocol ip prio 5 u32 \
+match ip tos 0x90 0xfc \
+$meter2 \
+continue flowid :2
+#
+# if it exceeds the above but not the rule below, it gets a tcindex value
+# of 3 (policer 3)
+#
+$TC filter add dev $INDEV parent ffff: protocol ip prio 6 u32 \
+match ip tos 0x90 0xfc \
+$meter3 \
+drop flowid :3
+#
+# *********************** AF43 *************************** 
+#
+#AF43 (DSCP 0x26) from is passed on with a tcindex value 3
+#if it doesnt exceed its CIR/CBS
+#policer 3 is used. Note that this is shared with the AF41 and AF42
+#
+$TC filter add dev $INDEV parent ffff: protocol ip prio 6 u32 \
+match ip tos 0x98 0xfc \
+$meter3 \
+drop flowid :3
+#
+# *********************** BE *************************** 
+#
+# Anything else (not from the AF4*) gets discarded if it 
+# exceeds 1Mbps and by default goes to BE if it doesnt
+# Note that the BE class is also used by the AF4* in the worst
+# case
+#
+$TC filter add dev $INDEV parent ffff: protocol ip prio 7 u32 \
+match ip src 0/0\
+$meter4 \
+drop flowid :4
+
+######################## Egress side ########################
+
+# attach a dsmarker
+#
+$TC qdisc add $EGDEV handle 1:0 root dsmark indices 64
+#
+# values of the DSCP to change depending on the class
+#note that the ECN bits are masked out
+#
+#AF41 (0x88 is 0x22 shifted to the right by two bits)
+#
+$TC class change $EGDEV classid 1:1 dsmark mask 0x3 \
+       value 0x88
+#AF42
+$TC class change $EGDEV classid 1:2 dsmark mask 0x3 \
+       value 0x90
+#AF43
+$TC class change $EGDEV classid 1:3 dsmark mask 0x3 \
+       value 0x98
+#BE
+$TC class change $EGDEV classid 1:3 dsmark mask 0x3 \
+       value 0x0
+#
+#
+# The class mapping
+#
+$TC filter add $EGDEV parent 1:0 protocol ip prio 1 \
+          handle 1 tcindex classid 1:1
+$TC filter add $EGDEV parent 1:0 protocol ip prio 1 \
+          handle 2 tcindex  classid 1:2
+$TC filter add $EGDEV parent 1:0 protocol ip prio 1 \
+          handle 3 tcindex  classid 1:3
+$TC filter add $EGDEV parent 1:0 protocol ip prio 1 \
+          handle 4 tcindex  classid 1:4
+#
+
+#
+echo "---- qdisc parameters Ingress  ----------"
+$TC qdisc ls dev $INDEV
+echo "---- Class parameters Ingress  ----------"
+$TC class ls dev $INDEV
+echo "---- filter parameters Ingress ----------"
+$TC filter ls dev $INDEV parent ffff:
+
+echo "---- qdisc parameters Egress  ----------"
+$TC qdisc ls $EGDEV
+echo "---- Class parameters Egress  ----------"
+$TC class ls $EGDEV
+echo "---- filter parameters Egress ----------"
+$TC filter ls $EGDEV parent 1:0
+#
+#deleting the ingress qdisc
+#$TC qdisc del $INDEV ingress
diff --git a/iproute2/examples/diffserv/Edge31-cb-chains b/iproute2/examples/diffserv/Edge31-cb-chains
new file mode 100644
index 0000000..d7faae9
--- /dev/null
+++ b/iproute2/examples/diffserv/Edge31-cb-chains
@@ -0,0 +1,132 @@
+#! /bin/sh -x
+#
+# sample script on using the ingress capabilities
+# This script fwmark tags(IPchains) based on metering on the ingress 
+# interface the result is used for fast classification and re-marking
+# on the egress interface
+# This is an example of a color blind mode marker with no PIR configured
+# based on draft-wahjak-mcm-00.txt (section 3.1)
+#
+#path to various utilities;
+#change to reflect yours.
+#
+IPROUTE=/root/DS-6-beta/iproute2-990530-dsing
+TC=$IPROUTE/tc/tc
+IP=$IPROUTE/ip/ip
+IPCHAINS=/root/DS-6-beta/ipchains-1.3.9/ipchains
+INDEV=eth2
+EGDEV="dev eth1"
+CIR1=1500kbit
+CIR2=1000kbit
+
+#The CBS is about 60 MTU sized packets
+CBS1=90k
+CBS2=90k
+
+meter1="police rate $CIR1 burst $CBS1 "
+meter2="police rate $CIR1 burst $CBS2 "
+meter3="police rate $CIR2 burst $CBS1 "
+meter4="police rate $CIR2 burst $CBS2 "
+meter5="police rate $CIR2 burst $CBS2 "
+#
+# tag the rest of incoming packets from subnet 10.2.0.0/24 to fw value 1
+# tag all incoming packets from any other subnet to fw tag 2
+############################################################ 
+$IPCHAINS -A input -i $INDEV -s 0/0 -m 2
+$IPCHAINS -A input -i $INDEV -s 10.2.0.0/24 -m 1
+#
+############################################################ 
+# install the ingress qdisc on the ingress interface
+$TC qdisc add dev $INDEV handle ffff: ingress
+#
+############################################################ 
+
+# All packets are marked with a tcindex value which is used on the egress
+# tcindex 1 maps to AF41, 2->AF42, 3->AF43, 4->BE
+#
+############################################################ 
+# 
+# anything with fw tag of 1 is passed on with a tcindex value 1
+#if it doesnt exceed its allocated rate (CIR/CBS)
+# 
+$TC filter add dev $INDEV parent ffff: protocol ip prio 4 handle 1 fw \
+$meter1 \
+continue flowid 4:1
+#
+# if it exceeds the above but not the extra rate/burst below, it gets a 
+#tcindex value  of 2
+#
+$TC filter add dev $INDEV parent ffff: protocol ip prio 5 handle 1 fw \
+$meter2 \
+continue flowid 4:2
+#
+# if it exceeds the above but not the rule below, it gets a tcindex value
+# of 3
+#
+$TC filter add dev $INDEV parent ffff: protocol ip prio 6 handle 1 fw \
+$meter3 \
+drop flowid 4:3
+#
+# Anything else (not from the subnet 10.2.0.24/24) gets discarded if it 
+# exceeds 1Mbps and by default goes to BE if it doesnt
+#
+$TC filter add dev $INDEV parent ffff: protocol ip prio 6 handle 2 fw \
+$meter5 \
+drop flowid 4:4
+
+
+######################## Egress side ########################
+
+
+# attach a dsmarker
+#
+$TC qdisc add $EGDEV handle 1:0 root dsmark indices 64
+#
+# values of the DSCP to change depending on the class
+#note that the ECN bits are masked out
+#
+#AF41 (0x88 is 0x22 shifted to the right by two bits)
+#
+$TC class change $EGDEV classid 1:1 dsmark mask 0x3 \
+       value 0x88
+#AF42
+$TC class change $EGDEV classid 1:2 dsmark mask 0x3 \
+       value 0x90
+#AF43
+$TC class change $EGDEV classid 1:3 dsmark mask 0x3 \
+       value 0x98
+#BE
+$TC class change $EGDEV classid 1:4 dsmark mask 0x3 \
+       value 0x0
+#
+#
+# The class mapping (using tcindex; could easily have
+# replaced it with the fw classifier instead)
+#
+$TC filter add $EGDEV parent 1:0 protocol ip prio 1 \
+          handle 1 tcindex classid 1:1
+$TC filter add $EGDEV parent 1:0 protocol ip prio 1 \
+          handle 2 tcindex  classid 1:2
+$TC filter add $EGDEV parent 1:0 protocol ip prio 1 \
+          handle 3 tcindex  classid 1:3
+$TC filter add $EGDEV parent 1:0 protocol ip prio 1 \
+          handle 4 tcindex  classid 1:4
+#
+
+#
+echo "---- qdisc parameters Ingress  ----------"
+$TC qdisc ls dev $INDEV
+echo "---- Class parameters Ingress  ----------"
+$TC class ls dev $INDEV
+echo "---- filter parameters Ingress ----------"
+$TC filter ls dev $INDEV parent ffff:
+
+echo "---- qdisc parameters Egress  ----------"
+$TC qdisc ls $EGDEV
+echo "---- Class parameters Egress  ----------"
+$TC class ls $EGDEV
+echo "---- filter parameters Egress ----------"
+$TC filter ls $EGDEV parent 1:0
+#
+#deleting the ingress qdisc
+#$TC qdisc del $INDEV ingress
diff --git a/iproute2/examples/diffserv/Edge32-ca-u32 b/iproute2/examples/diffserv/Edge32-ca-u32
new file mode 100644
index 0000000..edf21e4
--- /dev/null
+++ b/iproute2/examples/diffserv/Edge32-ca-u32
@@ -0,0 +1,198 @@
+#! /bin/sh -x
+#
+# sample script on using the ingress capabilities using u32 classifier
+# This script tags tcindex based on metering on the ingress 
+# interface the result is used for fast classification and re-marking
+# on the egress interface
+# This is an example of a color aware mode marker with PIR configured
+# based on draft-wahjak-mcm-00.txt (section 3.2)
+#
+# The colors are defined using the Diffserv Fields
+#path to various utilities;
+#change to reflect yours.
+#
+IPROUTE=/root/DS-6-beta/iproute2-990530-dsing
+TC=$IPROUTE/tc/tc
+IP=$IPROUTE/ip/ip
+IPCHAINS=/root/DS-6-beta/ipchains-1.3.9/ipchains
+INDEV=eth2
+EGDEV="dev eth1"
+CIR1=1000kbit
+CIR2=500kbit
+# the PIR is what is in excess of the CIR
+PIR1=1000kbit
+PIR2=500kbit
+
+#The CBS is about 60 MTU sized packets
+CBS1=90k
+CBS2=90k
+#the EBS is about 20 max sized packets
+EBS1=30k
+EBS2=30k
+
+# The meters: Note that we have shared meters in this case as identified
+# by the index parameter
+meter1=" police index 1 rate $CIR1 burst $CBS1 "
+meter1a=" police index 2 rate $PIR1 burst $EBS1 "
+meter2=" police index 3 rate $CIR2 burst $CBS1 "
+meter2a=" police index 4 rate $PIR2 burst $EBS1 "
+meter3=" police index 5 rate $CIR2 burst $CBS2 "
+meter3a=" police index 6 rate $PIR2 burst $EBS2 "
+meter4=" police index 7 rate $CIR1 burst $CBS2 "
+
+############################################################ 
+#
+# install the ingress qdisc on the ingress interface
+$TC qdisc add dev $INDEV handle ffff: ingress
+############################################################ 
+#
+# All packets are marked with a tcindex value which is used on the egress
+# tcindex 1 maps to AF41, 2->AF42, 3->AF43, 4->BE
+#
+# *********************** AF41 *************************** 
+#AF41 (DSCP 0x22) from is passed on with a tcindex value 1
+#if it doesnt exceed its CIR/CBS + PIR/EBS
+#policer 1  is used.
+#
+$TC filter add dev $INDEV parent ffff: protocol ip prio 1 u32 \
+match ip tos 0x88 0xfc \
+$meter1 \
+continue flowid :1
+$TC filter add dev $INDEV parent ffff: protocol ip prio 2 u32 \
+match ip tos 0x88 0xfc \
+$meter1a \
+continue flowid :1
+#
+# if it exceeds the above but not the extra rate/burst below, it gets a 
+# tcindex value  of 2
+# policer 2 is used
+#
+$TC filter add dev $INDEV parent ffff: protocol ip prio 3 u32 \
+match ip tos 0x88 0xfc \
+$meter2 \
+continue flowid :2
+$TC filter add dev $INDEV parent ffff: protocol ip prio 4 u32 \
+match ip tos 0x88 0xfc \
+$meter2a \
+continue flowid :2
+#
+# if it exceeds the above but not the rule below, it gets a tcindex value
+# of 3 (policer 3)
+#
+$TC filter add dev $INDEV parent ffff: protocol ip prio 5 u32 \
+match ip tos 0x88 0xfc \
+$meter3 \
+continue flowid :3
+$TC filter add dev $INDEV parent ffff: protocol ip prio 6 u32 \
+match ip tos 0x88 0xfc \
+$meter3a \
+drop flowid :3
+#
+# *********************** AF42 *************************** 
+#AF42 (DSCP 0x24) from is passed on with a tcindex value 2
+#if it doesnt exceed its CIR/CBS + PIR/EBS
+#policer 2 is used. Note that this is shared with the AF41
+#
+#
+$TC filter add dev $INDEV parent ffff: protocol ip prio 8 u32 \
+match ip tos 0x90 0xfc \
+$meter2 \
+continue flowid :2
+$TC filter add dev $INDEV parent ffff: protocol ip prio 9 u32 \
+match ip tos 0x90 0xfc \
+$meter2a \
+continue flowid :2
+#
+# if it exceeds the above but not the rule below, it gets a tcindex value
+# of 3 (policer 3)
+#
+$TC filter add dev $INDEV parent ffff: protocol ip prio 10 u32 \
+match ip tos 0x90 0xfc \
+$meter3 \
+continue flowid :3
+$TC filter add dev $INDEV parent ffff: protocol ip prio 11 u32 \
+match ip tos 0x90 0xfc \
+$meter3a \
+drop flowid :3
+
+#
+# *********************** AF43 *************************** 
+#
+#AF43 (DSCP 0x26) from is passed on with a tcindex value 3
+#if it doesnt exceed its CIR/CBS + PIR/EBS
+#policer 3 is used. Note that this is shared with the AF41 and AF42
+#
+$TC filter add dev $INDEV parent ffff: protocol ip prio 13 u32 \
+match ip tos 0x98 0xfc \
+$meter3 \
+continue flowid :3
+$TC filter add dev $INDEV parent ffff: protocol ip prio 14 u32 \
+match ip tos 0x98 0xfc \
+$meter3a \
+drop flowid :3
+#
+## *********************** BE *************************** 
+##
+## Anything else (not from the AF4*) gets discarded if it 
+## exceeds 1Mbps and by default goes to BE if it doesnt
+## Note that the BE class is also used by the AF4* in the worst
+## case
+##
+$TC filter add dev $INDEV parent ffff: protocol ip prio 16 u32 \
+match ip src 0/0\
+$meter4 \
+drop flowid :4
+
+######################## Egress side ########################
+
+# attach a dsmarker
+#
+$TC qdisc add $EGDEV handle 1:0 root dsmark indices 64
+#
+# values of the DSCP to change depending on the class
+#note that the ECN bits are masked out
+#
+#AF41 (0x88 is 0x22 shifted to the right by two bits)
+#
+$TC class change $EGDEV classid 1:1 dsmark mask 0x3 \
+       value 0x88
+#AF42
+$TC class change $EGDEV classid 1:2 dsmark mask 0x3 \
+       value 0x90
+#AF43
+$TC class change $EGDEV classid 1:3 dsmark mask 0x3 \
+       value 0x98
+#BE
+$TC class change $EGDEV classid 1:3 dsmark mask 0x3 \
+       value 0x0
+#
+#
+# The class mapping
+#
+$TC filter add $EGDEV parent 1:0 protocol ip prio 1 \
+          handle 1 tcindex classid 1:1
+$TC filter add $EGDEV parent 1:0 protocol ip prio 1 \
+          handle 2 tcindex  classid 1:2
+$TC filter add $EGDEV parent 1:0 protocol ip prio 1 \
+          handle 3 tcindex  classid 1:3
+$TC filter add $EGDEV parent 1:0 protocol ip prio 1 \
+          handle 4 tcindex  classid 1:4
+#
+
+#
+echo "---- qdisc parameters Ingress  ----------"
+$TC qdisc ls dev $INDEV
+echo "---- Class parameters Ingress  ----------"
+$TC class ls dev $INDEV
+echo "---- filter parameters Ingress ----------"
+$TC filter ls dev $INDEV parent ffff:
+
+echo "---- qdisc parameters Egress  ----------"
+$TC qdisc ls $EGDEV
+echo "---- Class parameters Egress  ----------"
+$TC class ls $EGDEV
+echo "---- filter parameters Egress ----------"
+$TC filter ls $EGDEV parent 1:0
+#
+#deleting the ingress qdisc
+#$TC qdisc del $INDEV ingress
diff --git a/iproute2/examples/diffserv/Edge32-cb-chains b/iproute2/examples/diffserv/Edge32-cb-chains
new file mode 100644
index 0000000..804fad1
--- /dev/null
+++ b/iproute2/examples/diffserv/Edge32-cb-chains
@@ -0,0 +1,144 @@
+#! /bin/sh -x
+#
+# sample script on using the ingress capabilities
+# This script fwmark tags(IPchains) based on metering on the ingress 
+# interface the result is used for fast classification and re-marking
+# on the egress interface
+# This is an example of a color blind mode marker with no PIR configured
+# based on draft-wahjak-mcm-00.txt (section 3.1)
+#
+#path to various utilities;
+#change to reflect yours.
+#
+IPROUTE=/root/DS-6-beta/iproute2-990530-dsing
+TC=$IPROUTE/tc/tc
+IP=$IPROUTE/ip/ip
+IPCHAINS=/root/DS-6-beta/ipchains-1.3.9/ipchains
+INDEV=eth2
+EGDEV="dev eth1"
+CIR1=1500kbit
+CIR2=500kbit
+
+#The CBS is about 60 MTU sized packets
+CBS1=90k
+CBS2=90k
+
+meter1="police rate $CIR1 burst $CBS1 "
+meter1a="police rate $CIR2 burst $CBS1 "
+meter2="police rate $CIR1 burst $CBS2 "
+meter2a="police rate $CIR2 burst $CBS2 "
+meter3="police rate $CIR2 burst $CBS1 "
+meter3a="police rate $CIR2 burst $CBS1 "
+meter4="police rate $CIR2 burst $CBS2 "
+meter5="police rate $CIR1 burst $CBS2 "
+#
+# tag the rest of incoming packets from subnet 10.2.0.0/24 to fw value 1
+# tag all incoming packets from any other subnet to fw tag 2
+############################################################ 
+$IPCHAINS -A input -i $INDEV -s 0/0 -m 2
+$IPCHAINS -A input -i $INDEV -s 10.2.0.0/24 -m 1
+#
+############################################################ 
+# install the ingress qdisc on the ingress interface
+$TC qdisc add dev $INDEV handle ffff: ingress
+#
+############################################################ 
+
+# All packets are marked with a tcindex value which is used on the egress
+# tcindex 1 maps to AF41, 2->AF42, 3->AF43, 4->BE
+#
+############################################################ 
+# 
+# anything with fw tag of 1 is passed on with a tcindex value 1
+#if it doesnt exceed its allocated rate (CIR/CBS)
+# 
+$TC filter add dev $INDEV parent ffff: protocol ip prio 1 handle 1 fw \
+$meter1 \
+continue flowid 4:1
+$TC filter add dev $INDEV parent ffff: protocol ip prio 2 handle 1 fw \
+$meter1a \
+continue flowid 4:1
+#
+# if it exceeds the above but not the extra rate/burst below, it gets a 
+#tcindex value  of 2
+#
+$TC filter add dev $INDEV parent ffff: protocol ip prio 3 handle 1 fw \
+$meter2 \
+continue flowid 4:2
+$TC filter add dev $INDEV parent ffff: protocol ip prio 4 handle 1 fw \
+$meter2a \
+continue flowid 4:2
+#
+# if it exceeds the above but not the rule below, it gets a tcindex value
+# of 3
+#
+$TC filter add dev $INDEV parent ffff: protocol ip prio 5 handle 1 fw \
+$meter3 \
+continue flowid 4:3
+$TC filter add dev $INDEV parent ffff: protocol ip prio 6 handle 1 fw \
+$meter3a \
+drop flowid 4:3
+#
+# Anything else (not from the subnet 10.2.0.24/24) gets discarded if it 
+# exceeds 1Mbps and by default goes to BE if it doesnt
+#
+$TC filter add dev $INDEV parent ffff: protocol ip prio 7 handle 2 fw \
+$meter5 \
+drop flowid 4:4
+
+
+######################## Egress side ########################
+
+
+# attach a dsmarker
+#
+$TC qdisc add $EGDEV handle 1:0 root dsmark indices 64
+#
+# values of the DSCP to change depending on the class
+#note that the ECN bits are masked out
+#
+#AF41 (0x88 is 0x22 shifted to the right by two bits)
+#
+$TC class change $EGDEV classid 1:1 dsmark mask 0x3 \
+       value 0x88
+#AF42
+$TC class change $EGDEV classid 1:2 dsmark mask 0x3 \
+       value 0x90
+#AF43
+$TC class change $EGDEV classid 1:3 dsmark mask 0x3 \
+       value 0x98
+#BE
+$TC class change $EGDEV classid 1:4 dsmark mask 0x3 \
+       value 0x0
+#
+#
+# The class mapping (using tcindex; could easily have
+# replaced it with the fw classifier instead)
+#
+$TC filter add $EGDEV parent 1:0 protocol ip prio 1 \
+          handle 1 tcindex classid 1:1
+$TC filter add $EGDEV parent 1:0 protocol ip prio 1 \
+          handle 2 tcindex  classid 1:2
+$TC filter add $EGDEV parent 1:0 protocol ip prio 1 \
+          handle 3 tcindex  classid 1:3
+$TC filter add $EGDEV parent 1:0 protocol ip prio 1 \
+          handle 4 tcindex  classid 1:4
+#
+
+#
+echo "---- qdisc parameters Ingress  ----------"
+$TC qdisc ls dev $INDEV
+echo "---- Class parameters Ingress  ----------"
+$TC class ls dev $INDEV
+echo "---- filter parameters Ingress ----------"
+$TC filter ls dev $INDEV parent ffff:
+
+echo "---- qdisc parameters Egress  ----------"
+$TC qdisc ls $EGDEV
+echo "---- Class parameters Egress  ----------"
+$TC class ls $EGDEV
+echo "---- filter parameters Egress ----------"
+$TC filter ls $EGDEV parent 1:0
+#
+#deleting the ingress qdisc
+#$TC qdisc del $INDEV ingress
diff --git a/iproute2/examples/diffserv/Edge32-cb-u32 b/iproute2/examples/diffserv/Edge32-cb-u32
new file mode 100644
index 0000000..cc2ebb4
--- /dev/null
+++ b/iproute2/examples/diffserv/Edge32-cb-u32
@@ -0,0 +1,145 @@
+#! /bin/sh 
+#
+# sample script on using the ingress capabilities using u32 classifier
+# This script tags tcindex based on metering on the ingress 
+# interface the result is used for fast classification and re-marking
+# on the egress interface
+# This is an example of a color blind mode marker with PIR configured
+# based on draft-wahjak-mcm-00.txt (section 3.2)
+#
+#path to various utilities;
+#change to reflect yours.
+#
+IPROUTE=/root/DS-6-beta/iproute2-990530-dsing
+TC=$IPROUTE/tc/tc
+IP=$IPROUTE/ip/ip
+INDEV=eth2
+EGDEV="dev eth1"
+CIR1=1000kbit
+CIR2=1000kbit
+# The PIR is the excess (in addition to the CIR i.e if always
+# going to the PIR --> average rate is CIR+PIR)
+PIR1=1000kbit
+PIR2=500kbit
+
+#The CBS is about 60 MTU sized packets
+CBS1=90k
+CBS2=90k
+#the EBS is about 10 max sized packets
+EBS1=15k
+EBS2=15k
+# The meters
+meter1=" police rate $CIR1 burst $CBS1 "
+meter1a=" police rate $PIR1 burst $EBS1 "
+meter2=" police rate $CIR2 burst $CBS1 "
+meter2a="police rate $PIR2 burst $CBS1 "
+meter3=" police rate $CIR2 burst $CBS2 "
+meter3a=" police rate $PIR2 burst $EBS2 "
+meter4=" police rate $CIR1 burst $CBS2 "
+meter5=" police rate $CIR1 burst $CBS2 "
+
+
+# install the ingress qdisc on the ingress interface
+############################################################ 
+$TC qdisc add dev $INDEV handle ffff: ingress
+############################################################ 
+#
+############################################################ 
+
+# All packets are marked with a tcindex value which is used on the egress
+# NOTE: tcindex 1 maps to AF41, 2->AF42, 3->AF43, 4->BE
+# 
+#anything from subnet 10.2.0.2/24 is passed on with a tcindex value 1
+#if it doesnt exceed its CIR/CBS + PIR/EBS
+# 
+$TC filter add dev $INDEV parent ffff: protocol ip prio 1 u32 \
+match ip src 10.2.0.0/24 $meter1 \
+continue flowid :1
+$TC filter add dev $INDEV parent ffff: protocol ip prio 2 u32 \
+match ip src 10.2.0.0/24 $meter1a \
+continue flowid :1
+
+#
+# if it exceeds the above but not the extra rate/burst below, it gets a 
+#tcindex value  of 2
+#
+$TC filter add dev $INDEV parent ffff: protocol ip prio 3 u32 \
+match ip src 10.2.0.0/24 $meter2 \
+continue flowid :2
+$TC filter add dev $INDEV parent ffff: protocol ip prio 4 u32 \
+match ip src 10.2.0.0/24 $meter2a \
+continue flowid :2
+#
+# if it exceeds the above but not the rule below, it gets a tcindex value
+# of 3
+#
+$TC filter add dev $INDEV parent ffff: protocol ip prio 5 u32 \
+match ip src 10.2.0.0/24 $meter3 \
+continue flowid :3
+$TC filter add dev $INDEV parent ffff: protocol ip prio 6 u32 \
+match ip src 10.2.0.0/24 $meter3a \
+drop flowid :3
+#
+#
+# Anything else (not from the subnet 10.2.0.24/24) gets discarded if it 
+# exceeds 1Mbps and by default goes to BE if it doesnt
+#
+$TC filter add dev $INDEV parent ffff: protocol ip prio 7 u32 \
+match ip src 0/0 $meter5 \
+drop flowid :4
+
+
+######################## Egress side ########################
+
+
+# attach a dsmarker
+#
+$TC qdisc add $EGDEV handle 1:0 root dsmark indices 64
+#
+# values of the DSCP to change depending on the class
+#note that the ECN bits are masked out
+#
+#AF41 (0x88 is 0x22 shifted to the right by two bits)
+#
+$TC class change $EGDEV classid 1:1 dsmark mask 0x3 \
+       value 0x88
+#AF42
+$TC class change $EGDEV classid 1:2 dsmark mask 0x3 \
+       value 0x90
+#AF43
+$TC class change $EGDEV classid 1:3 dsmark mask 0x3 \
+       value 0x98
+#BE
+$TC class change $EGDEV classid 1:3 dsmark mask 0x3 \
+       value 0x0
+#
+#
+# The class mapping
+#
+$TC filter add $EGDEV parent 1:0 protocol ip prio 1 \
+          handle 1 tcindex classid 1:1
+$TC filter add $EGDEV parent 1:0 protocol ip prio 1 \
+          handle 2 tcindex  classid 1:2
+$TC filter add $EGDEV parent 1:0 protocol ip prio 1 \
+          handle 3 tcindex  classid 1:3
+$TC filter add $EGDEV parent 1:0 protocol ip prio 1 \
+          handle 4 tcindex  classid 1:4
+#
+
+#
+echo "---- qdisc parameters Ingress  ----------"
+$TC qdisc ls dev $INDEV
+echo "---- Class parameters Ingress  ----------"
+$TC class ls dev $INDEV
+echo "---- filter parameters Ingress ----------"
+$TC filter ls dev $INDEV parent ffff:
+
+echo "---- qdisc parameters Egress  ----------"
+$TC qdisc ls $EGDEV
+echo "---- Class parameters Egress  ----------"
+$TC class ls $EGDEV
+echo "---- filter parameters Egress ----------"
+$TC filter ls $EGDEV parent 1:0
+#
+#deleting the ingress qdisc
+#$TC qdisc del $INDEV ingress
diff --git a/iproute2/examples/diffserv/README b/iproute2/examples/diffserv/README
new file mode 100644
index 0000000..ec91d63
--- /dev/null
+++ b/iproute2/examples/diffserv/README
@@ -0,0 +1,98 @@
+
+Note all these are mere examples which can be customized to your needs
+
+AFCBQ
+-----
+AF PHB built using CBQ, DSMARK,GRED (default in GRIO mode) ,RED for BE 
+and the tcindex classifier with some algorithmic mapping
+
+EFCBQ
+-----
+EF PHB built using CBQ (for rate control and prioritization), 
+DSMARK( to remark DSCPs), tcindex  classifier and  RED for the BE
+traffic.
+
+EFPRIO
+------
+EF PHB using the PRIO scheduler, Token Bucket to rate control EF,
+tcindex classifier, DSMARK to remark, and RED for the BE traffic
+
+EDGE scripts
+==============
+
+CB-3(1|2)-(u32/chains)
+======================
+
+
+The major differences are that the classifier is u32 on -u32 extension
+and IPchains on the chains extension. CB stands for color Blind
+and 31 is for the mode where only a CIR and CBS are defined whereas
+32 stands for a mode where a CIR/CBS + PIR/EBS are defined.
+
+Color Blind (CB)
+==========-----=
+We look at one special subnet that we are interested in for simplicty
+reasons to demonstrate the capability. We send the packets from that
+subnet to AF4*, BE or end up dropping depending on the metering results. 
+
+
+The algorithm overview is as follows:
+
+*classify:
+
+**case: subnet X
+----------------
+  if !exceed meter1 tag as AF41
+	else
+	    if !exceed meter2  tag as AF42
+	        else
+		  if !exceed meter 3 tag as AF43
+		      else 
+			 drop 
+
+default case: Any other subnet
+-------------------------------
+  if !exceed meter 5 tag as AF43
+      else
+	 drop 
+
+
+One Egress side change the DSCPs of the packets to reflect AF4* and BE
+based on the tags from the ingress.
+
+-------------------------------------------------------------
+
+Color Aware
+===========
+
+Define some meters with + policing and give them IDs eg
+
+meter1=police index 1 rate $CIR1 burst $CBS1  
+meter2=police index 2 rate $CIR2 burst $CBS2   etc 
+
+General overview:
+classify based on the DSCPs and use the policer ids to decide tagging
+
+
+*classify on ingress:
+
+switch (dscp) {
+    case AF41: /* tos&0xfc == 0x88 */
+	if (!exceed meter1) break;
+    case AF42: /* tos&0xfc == 0x90 */
+	if (!exceed meter2) {
+	    tag as AF42;
+	    break;
+	}
+    case AF43: /* tos&0xfc == 0x98 */
+	if (!exceed meter3) {
+	    tag as AF43;
+	    break;
+	} else
+	  drop;
+    default:
+	if (!exceed meter4) tag as BE;
+	else drop;
+}
+
+On the Egress side mark the proper AF tags
diff --git a/iproute2/examples/diffserv/afcbq b/iproute2/examples/diffserv/afcbq
new file mode 100644
index 0000000..10d6d93
--- /dev/null
+++ b/iproute2/examples/diffserv/afcbq
@@ -0,0 +1,105 @@
+#!/usr/bin/perl
+#
+#
+# AF using CBQ for a single interface eth0 
+# 4 AF classes using GRED and one BE using RED
+# Things you might want to change:
+#	- the device bandwidth (set at 10Mbits)
+#	- the bandwidth allocated for each AF class and the BE class	
+#	- the drop probability associated with each AF virtual queue
+#
+# AF DSCP values used (based on AF draft 04)
+# -----------------------------------------
+# AF DSCP values
+# AF1 1. 0x0a 2. 0x0c 3. 0x0e
+# AF2 1. 0x12 2. 0x14 3. 0x16
+# AF3 1. 0x1a 2. 0x1c 3. 0x1e
+# AF4 1. 0x22 2. 0x24 3. 0x26
+
+#
+# 
+# A simple DSCP-class relationship formula used to generate
+# values in the for loop of this script; $drop stands for the
+# DP
+#	$dscp = ($class*8+$drop*2)
+#
+#  if you use GRIO buffer sharing, then GRED priority is set as follows:
+#  $gprio=$drop+1; 
+#
+
+$TC = "/usr/src/iproute2-current/tc/tc";
+$DEV = "dev lo";
+$DEV = "dev eth1";
+$DEV = "dev eth0";
+# the BE-class number
+$beclass = "5";  
+
+#GRIO buffer sharing on or off?
+$GRIO = "";
+$GRIO = "grio";
+# The bandwidth of your device
+$linerate="10Mbit";
+# The BE and AF rates
+%rate_table=();
+$berate="1500Kbit";
+$rate_table{"AF1rate"}="1500Kbit";
+$rate_table{"AF2rate"}="1500Kbit";
+$rate_table{"AF3rate"}="1500Kbit";
+$rate_table{"AF4rate"}="1500Kbit";
+#
+#
+#
+print "\n# --- General setup  ---\n";
+print "$TC qdisc add $DEV handle 1:0 root dsmark indices 64 set_tc_index\n";
+print "$TC filter add $DEV parent 1:0 protocol ip prio 1 tcindex mask 0xfc " .
+   "shift 2 pass_on\n";
+   #"shift 2\n";
+print "$TC qdisc add $DEV parent 1:0 handle 2:0 cbq bandwidth $linerate ".
+  "cell 8 avpkt 1000 mpu 64\n";
+print "$TC filter add $DEV parent 2:0 protocol ip prio 1 tcindex ".
+  "mask 0xf0 shift 4 pass_on\n";
+for $class (1..4) {
+    print "\n# --- AF Class $class specific setup---\n";
+    $AFrate=sprintf("AF%drate",$class);
+    print "$TC class add $DEV parent 2:0 classid 2:$class cbq ".
+      "bandwidth $linerate rate $rate_table{$AFrate} avpkt 1000 prio ".
+      (6-$class)." bounded allot 1514 weight 1 maxburst 21\n";
+    print "$TC filter add $DEV parent 2:0 protocol ip prio 1 handle $class ".
+      "tcindex classid 2:$class\n";
+    print "$TC qdisc add $DEV parent 2:$class gred setup DPs 3 default 2 ".
+      "$GRIO\n";
+# 
+# per DP setup
+#
+    for $drop (1..3) {
+    print "\n# --- AF Class $class DP $drop---\n";
+	$dscp = $class*8+$drop*2;
+	$tcindex = sprintf("1%x%x",$class,$drop);
+	print "$TC filter add $DEV parent 1:0 protocol ip prio 1 ".
+	  "handle $dscp tcindex classid 1:$tcindex\n";
+	$prob = $drop*0.02;
+        if ($GRIO) {
+	$gprio = $drop+1;
+	print "$TC qdisc change $DEV parent 2:$class gred limit 60KB min 15KB ".
+	  "max 45KB burst 20 avpkt 1000 bandwidth $linerate DP $drop ".
+	  "probability $prob ".
+          "prio $gprio\n";
+        } else {
+	print "$TC qdisc change $DEV parent 2:$class gred limit 60KB min 15KB ".
+	  "max 45KB burst 20 avpkt 1000 bandwidth $linerate DP $drop ".
+	  "probability $prob \n";
+	}
+    }
+}
+#
+#
+print "\n#------BE Queue setup------\n";
+print "$TC filter add $DEV parent 1:0 protocol ip prio 2 ".
+          "handle 0 tcindex mask 0 classid 1:1\n";
+print "$TC class add $DEV parent 2:0 classid 2:$beclass cbq ".
+      "bandwidth $linerate rate $berate avpkt 1000 prio 6 " .
+      "bounded allot 1514 weight 1 maxburst 21 \n";
+print "$TC filter add $DEV parent 2:0 protocol ip prio 1 handle 0 tcindex ".
+  "classid 2:5\n";
+print "$TC qdisc add $DEV parent 2:5 red limit 60KB min 15KB max 45KB ".
+  "burst 20 avpkt 1000 bandwidth $linerate probability 0.4\n";
diff --git a/iproute2/examples/diffserv/ef-prio b/iproute2/examples/diffserv/ef-prio
new file mode 100644
index 0000000..48611bd
--- /dev/null
+++ b/iproute2/examples/diffserv/ef-prio
@@ -0,0 +1,25 @@
+#!/usr/bin/perl
+$TC = "/root/DS-6-beta/iproute2-990530-dsing/tc/tc";
+$DEV = "dev eth1";
+$efrate="1.5Mbit";
+$MTU="1.5kB";
+print "$TC qdisc add $DEV handle 1:0 root dsmark indices 64 set_tc_index\n";
+print "$TC filter add $DEV parent 1:0 protocol ip prio 1 tcindex ".
+  "mask 0xfc shift 2\n";
+print "$TC qdisc add $DEV parent 1:0 handle 2:0 prio\n";
+#
+# EF class: Maximum about one MTU sized packet allowed on the queue
+#
+print "$TC qdisc add $DEV parent 2:1 tbf rate $efrate burst $MTU limit 1.6kB\n";
+print "$TC filter add $DEV parent 2:0 protocol ip prio 1 ".
+	  "handle 0x2e tcindex classid 2:1 pass_on\n";
+#
+# BE class
+#
+print "#BE class(2:2) \n";
+print "$TC qdisc add $DEV parent 2:2 red limit 60KB ".
+	  "min 15KB max 45KB burst 20 avpkt 1000 bandwidth 10Mbit ".
+	  "probability 0.4\n";
+#
+print "$TC filter add $DEV parent 2:0 protocol ip prio 2 ".
+	  "handle 0 tcindex mask 0 classid 2:2 pass_on\n";
diff --git a/iproute2/examples/diffserv/efcbq b/iproute2/examples/diffserv/efcbq
new file mode 100644
index 0000000..bcc437b
--- /dev/null
+++ b/iproute2/examples/diffserv/efcbq
@@ -0,0 +1,31 @@
+#!/usr/bin/perl
+#
+$TC = "/root/DS-6-beta/iproute2-990530-dsing/tc/tc";
+$DEV = "dev eth1";
+print "$TC qdisc add $DEV handle 1:0 root dsmark indices 64 set_tc_index\n";
+print "$TC filter add $DEV parent 1:0 protocol ip prio 1 tcindex ".
+  "mask 0xfc shift 2\n";
+print "$TC qdisc add $DEV parent 1:0 handle 2:0 cbq bandwidth ".
+	"10Mbit cell 8 avpkt 1000 mpu 64\n";
+#
+# EF class
+#
+print "$TC class add $DEV parent 2:0 classid 2:1 cbq bandwidth ". 
+	"10Mbit rate 1500Kbit avpkt 1000 prio 1 bounded isolated ".
+	"allot 1514 weight 1 maxburst 10 \n";
+# packet fifo for EF?
+print "$TC qdisc add $DEV parent 2:1 pfifo limit 5\n";
+print "$TC filter add $DEV parent 2:0 protocol ip prio 1 ".
+	  "handle 0x2e tcindex classid 2:1 pass_on\n";
+#
+# BE class
+#
+print "#BE class(2:2) \n";
+print "$TC class add $DEV parent 2:0 classid 2:2 cbq bandwidth ". 
+	"10Mbit rate 5Mbit avpkt 1000 prio 7 allot 1514 weight 1 ".
+	"maxburst 21 borrow split 2:0 defmap 0xffff \n";
+print "$TC qdisc add $DEV parent 2:2 red limit 60KB ".
+	  "min 15KB max 45KB burst 20 avpkt 1000 bandwidth 10Mbit ".
+	  "probability 0.4\n";
+print "$TC filter add $DEV parent 2:0 protocol ip prio 2 ".
+	  "handle 0 tcindex mask 0 classid 2:2 pass_on\n";
diff --git a/iproute2/examples/diffserv/regression-testing b/iproute2/examples/diffserv/regression-testing
new file mode 100644
index 0000000..0ec705c
--- /dev/null
+++ b/iproute2/examples/diffserv/regression-testing
@@ -0,0 +1,125 @@
+
+These were the tests done to validate the Diffserv scripts.
+This document will be updated continously. If you do more
+thorough validation testing please post the details to the
+diffserv mailing list. 
+Nevertheless, these tests should serve for basic validation.
+
+AFCBQ, EFCBQ, EFPRIO
+----------------------
+
+generate all possible DSCPs and observe that they 
+get sent to the proper classes. In the case of AF also
+to the correct Virtual Queues.
+
+Edge1
+-----
+generate TOS values 0x0,0x10,0xbb each with IP addresses
+10.2.0.24 (mark 1), 10.2.0.3 (mark2) and 10.2.0.30 (mark 3)
+and observe that they get marked as expected.
+
+Edge2
+-----
+
+-Repeat the tests in Edge1
+-ftp with data direction from 10.2.0.2
+	*observe that the metering/policing works correctly (and the marking
+	as well). In this case the mark used will be 3
+
+Edge31-cb-chains
+----------------
+
+-ftp with data direction from 10.2.0.2
+
+	*observe that the metering/policing works correctly (and the marking
+	as well). In this case the mark used will be 1. 
+
+	Metering: The data throughput should not exceed 2*CIR1 + 2*CIR2
+	which is roughly: 5mbps
+
+	Marking: the should be a variation of marked packets:
+	AF41(TOS=0x88) AF42(0x90) AF43(0x98) and BE (0x0)
+
+More tests required to see the interaction of several sources (other
+than subnet 10.2.0.0/24).
+
+Edge31-ca-u32
+--------------
+
+Generate data using modified tcpblast from 10.2.0.2 (behind eth2) to the 
+discard port of 10.1.0.2 (behind eth1)
+
+1) generate with src tos = 0x88
+	Metering: Allocated throughput should not exceed 2*CIR1 + 2*CIR2
+	approximately 5mbps
+	Marking: Should vary between 0x88,0x90,0x98 and 0x0
+
+2) generate with src tos = 0x90
+	Metering: Allocated throughput should not exceed CIR1 + 2*CIR2
+	approximately 3.5mbps
+	Marking: Should vary between 0x90,0x98 and 0x0
+
+3) generate with src tos = 0x98
+	Metering: Allocated throughput should not exceed CIR1 + CIR2
+	approximately 2.5mbps
+	Marking: Should vary between 0x98 and 0x0
+
+4) generate with src tos any other than the above
+	Metering: Allocated throughput should not exceed CIR1 
+	approximately 1.5mbps
+	Marking: Should be consistent at 0x0
+
+TODO: Testing on how each color shares when all 4 types of packets
+are going through the edge device
+
+Edge32-cb-u32, Edge32-cb-chains
+-------------------------------
+
+-ftp with data direction from 10.2.0.2
+
+	*observe that the metering/policing works correctly (and the marking
+	as well). 
+
+	Metering: 
+        The data throughput should not exceed 2*CIR1 + 2*CIR2
+	+ 2*PIR2 + PIR1 for u32 which is roughly: 6mbps
+        The data throughput should not exceed 2*CIR1 + 5*CIR2
+	for chains which is roughly: 6mbps
+
+	Marking: the should be a variation of marked packets:
+	AF41(TOS=0x88) AF42(0x90) AF43(0x98) and BE (0x0)
+
+TODO:
+-More tests required to see the interaction of several sources (other
+than subnet 10.2.0.0/24).
+-More tests needed to capture stats on how many times the CIR was exceeded
+but the data was not remarked etc.
+
+Edge32-ca-u32
+--------------
+
+Generate data using modified tcpblast from 10.2.0.2 (behind eth2) to the 
+discard port of 10.1.0.2 (behind eth1)
+
+1) generate with src tos = 0x88
+	Metering: Allocated throughput should not exceed 2*CIR1 + 2*CIR2
+	+PIR1 -- approximately 4mbps
+	Marking: Should vary between 0x88,0x90,0x98 and 0x0
+
+2) generate with src tos = 0x90
+	Metering: Allocated throughput should not exceed CIR1 + 2*CIR2
+	+ 2* PIR2 approximately 3mbps
+	Marking: Should vary between 0x90,0x98 and 0x0
+
+3) generate with src tos = 0x98
+	Metering: Allocated throughput should not exceed PIR1+ CIR1 + CIR2
+	approximately 2.5mbps
+	Marking: Should vary between 0x98 and 0x0
+
+4) generate with src tos any other than the above
+	Metering: Allocated throughput should not exceed CIR1 
+	approximately 1mbps
+	Marking: Should be consistent at 0x0
+
+TODO: Testing on how each color shares when all 4 types of packets
+are going through the edge device
diff --git a/iproute2/examples/gaiconf b/iproute2/examples/gaiconf
new file mode 100644
index 0000000..d75292b
--- /dev/null
+++ b/iproute2/examples/gaiconf
@@ -0,0 +1,134 @@
+#!/bin/sh
+
+#
+# Setup address label from /etc/gai.conf
+#
+# Written by YOSHIFUJI Hideaki <yoshfuji@linux-ipv6.org>, 2010.
+#
+
+IP=ip
+DEFAULT_GAICONF=/etc/gai.conf
+verbose=
+debug=
+
+function run ()
+{
+	if [ x"$verbose" != x"" ]; then
+		echo "$@"
+	fi
+	if [ x"$debug" = x"" ]; then
+		"$@"
+	fi
+}
+
+function do_load_config ()
+{
+	file=$1; shift
+	flush=1
+	cat $file | while read command prefix label; do
+		if [ x"$command" = x"#label" ]; then
+			if [ ${flush} = 1 ]; then
+				run ${IP} -6 addrlabel flush
+				flush=0
+			fi
+			run ${IP} -6 addrlabel add prefix $prefix label $label
+		fi
+	done
+}
+
+function do_list_config ()
+{
+	${IP} -6 addrlabel list | while read p pfx l lbl; do
+		echo label ${pfx} ${lbl}
+	done
+}
+
+function help ()
+{
+	echo "Usage: $0 [-v] {--list | --config [ ${DEFAULT_GAICONF} ] | --default}"
+	exit 1
+}
+
+TEMP=`getopt -o c::dlv -l config::,default,list,verbose -n gaiconf -- "$@"`
+
+if [ $? != 0 ]; then
+	echo "Terminating..." >&2
+	exit 1
+fi
+
+TEMPFILE=`mktemp`
+
+eval set -- "$TEMP"
+
+while true ; do
+	case "$1" in
+		-c|--config)
+			if [ x"$cmd" != x"" ]; then
+				help
+			fi
+			case "$2" in
+			"")	gai_conf="${DEFAULT_GAICONF}"
+				shift 2
+				;;
+			*)	gai_conf="$2"
+				shift 2
+			esac
+			cmd=config
+			;;
+		-d|--default)
+			if [ x"$cmd" != x"" ]; then
+				help
+			fi
+			gai_conf=${TEMPFILE}
+			cmd=config
+			;;
+		-l|--list)
+			if [ x"$cmd" != x"" ]; then
+				help
+			fi
+			cmd=list
+			shift
+			;;
+		-v)
+			verbose=1
+			shift
+			;;
+		--)
+			shift;
+			break
+			;;
+		*)
+			echo "Internal error!" >&2
+			exit 1
+			;;
+	esac
+done
+
+case "$cmd" in
+	config)
+		if [ x"$gai_conf" = x"${TEMPFILE}" ]; then
+			sed -e 's/^[[:space:]]*//' <<END_OF_DEFAULT >${TEMPFILE}
+				label ::1/128       0
+				label ::/0          1
+				label 2002::/16     2
+				label ::/96         3
+				label ::ffff:0:0/96 4
+				label fec0::/10     5
+				label fc00::/7      6
+				label 2001:0::/32   7
+END_OF_DEFAULT
+		fi
+		do_load_config "$gai_conf"
+		;;
+	list)
+		do_list_config
+		;;
+	*)
+		help
+		;;
+esac
+
+rm -f "${TEMPFILE}"
+
+exit 0
+
diff --git a/iproute2/genl/Makefile b/iproute2/genl/Makefile
new file mode 100644
index 0000000..03d1f26
--- /dev/null
+++ b/iproute2/genl/Makefile
@@ -0,0 +1,40 @@
+GENLOBJ=genl.o
+
+include ../Config
+SHARED_LIBS ?= y
+
+CFLAGS += -fno-strict-aliasing
+
+GENLMODULES :=
+GENLMODULES += ctrl.o
+
+GENLOBJ += $(GENLMODULES)
+
+GENLLIB :=
+
+ifeq ($(SHARED_LIBS),y)
+LDFLAGS += -Wl,-export-dynamic
+LDLIBS  += -lm -ldl
+endif
+
+all: genl
+
+genl: $(GENLOBJ) $(LIBNETLINK) $(LIBUTIL) $(GENLLIB)
+
+install: all
+	install -m 0755 genl $(DESTDIR)$(SBINDIR)
+
+clean:
+	rm -f $(GENLOBJ) $(GENLLIB) genl
+
+ifneq ($(SHARED_LIBS),y)
+
+genl: static-syms.o
+static-syms.o: static-syms.h
+static-syms.h: $(wildcard *.c)
+	files="$^" ; \
+	for s in `grep -B 3 '\<dlsym' $$files | sed -n '/snprintf/{s:.*"\([^"]*\)".*:\1:;s:%s::;p}'` ; do \
+		sed -n '/'$$s'[^ ]* =/{s:.* \([^ ]*'$$s'[^ ]*\) .*:extern char \1[] __attribute__((weak)); if (!strcmp(sym, "\1")) return \1;:;p}' $$files ; \
+	done > $@
+
+endif
diff --git a/iproute2/genl/ctrl.c b/iproute2/genl/ctrl.c
new file mode 100644
index 0000000..b7a8878
--- /dev/null
+++ b/iproute2/genl/ctrl.c
@@ -0,0 +1,419 @@
+/*
+ * ctrl.c	generic netlink controller
+ *
+ *		This program is free software; you can distribute 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.
+ *
+ * Authors:	J Hadi Salim (hadi@cyberus.ca)
+ *		Johannes Berg (johannes@sipsolutions.net)
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <syslog.h>
+#include <fcntl.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <string.h>
+
+#include "utils.h"
+#include "genl_utils.h"
+
+#define GENL_MAX_FAM_OPS	256
+#define GENL_MAX_FAM_GRPS	256
+
+static int usage(void)
+{
+	fprintf(stderr,"Usage: ctrl <CMD>\n" \
+		       "CMD   := get <PARMS> | list | monitor\n" \
+		       "PARMS := name <name> | id <id>\n" \
+		       "Examples:\n" \
+		       "\tctrl ls\n" \
+		       "\tctrl monitor\n" \
+		       "\tctrl get name foobar\n" \
+		       "\tctrl get id 0xF\n");
+	return -1;
+}
+
+int genl_ctrl_resolve_family(const char *family)
+{
+	struct rtnl_handle rth;
+	struct nlmsghdr *nlh;
+	struct genlmsghdr *ghdr;
+	int ret = 0;
+	struct {
+		struct nlmsghdr         n;
+		char                    buf[4096];
+	} req;
+
+	memset(&req, 0, sizeof(req));
+
+	nlh = &req.n;
+	nlh->nlmsg_len = NLMSG_LENGTH(GENL_HDRLEN);
+	nlh->nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK;
+	nlh->nlmsg_type = GENL_ID_CTRL;
+
+	ghdr = NLMSG_DATA(&req.n);
+	ghdr->cmd = CTRL_CMD_GETFAMILY;
+
+	if (rtnl_open_byproto(&rth, 0, NETLINK_GENERIC) < 0) {
+		fprintf(stderr, "Cannot open generic netlink socket\n");
+		exit(1);
+	}
+
+	addattr_l(nlh, 128, CTRL_ATTR_FAMILY_NAME, family, strlen(family) + 1);
+
+	if (rtnl_talk(&rth, nlh, nlh, sizeof(req)) < 0) {
+		fprintf(stderr, "Error talking to the kernel\n");
+		goto errout;
+	}
+
+	{
+		struct rtattr *tb[CTRL_ATTR_MAX + 1];
+		struct genlmsghdr *ghdr = NLMSG_DATA(nlh);
+		int len = nlh->nlmsg_len;
+		struct rtattr *attrs;
+
+		if (nlh->nlmsg_type !=  GENL_ID_CTRL) {
+			fprintf(stderr, "Not a controller message, nlmsg_len=%d "
+				"nlmsg_type=0x%x\n", nlh->nlmsg_len, nlh->nlmsg_type);
+			goto errout;
+		}
+
+		if (ghdr->cmd != CTRL_CMD_NEWFAMILY) {
+			fprintf(stderr, "Unknown controller command %d\n", ghdr->cmd);
+			goto errout;
+		}
+
+		len -= NLMSG_LENGTH(GENL_HDRLEN);
+
+		if (len < 0) {
+			fprintf(stderr, "wrong controller message len %d\n", len);
+			return -1;
+		}
+
+		attrs = (struct rtattr *) ((char *) ghdr + GENL_HDRLEN);
+		parse_rtattr(tb, CTRL_ATTR_MAX, attrs, len);
+
+		if (tb[CTRL_ATTR_FAMILY_ID] == NULL) {
+			fprintf(stderr, "Missing family id TLV\n");
+			goto errout;
+		}
+
+		ret = rta_getattr_u16(tb[CTRL_ATTR_FAMILY_ID]);
+	}
+
+errout:
+	rtnl_close(&rth);
+	return ret;
+}
+
+static void print_ctrl_cmd_flags(FILE *fp, __u32 fl)
+{
+	fprintf(fp, "\n\t\tCapabilities (0x%x):\n ", fl);
+	if (!fl) {
+		fprintf(fp, "\n");
+		return;
+	}
+	fprintf(fp, "\t\t ");
+
+	if (fl & GENL_ADMIN_PERM)
+		fprintf(fp, " requires admin permission;");
+	if (fl & GENL_CMD_CAP_DO)
+		fprintf(fp, " can doit;");
+	if (fl & GENL_CMD_CAP_DUMP)
+		fprintf(fp, " can dumpit;");
+	if (fl & GENL_CMD_CAP_HASPOL)
+		fprintf(fp, " has policy");
+
+	fprintf(fp, "\n");
+}
+	
+static int print_ctrl_cmds(FILE *fp, struct rtattr *arg, __u32 ctrl_ver)
+{
+	struct rtattr *tb[CTRL_ATTR_OP_MAX + 1];
+
+	if (arg == NULL)
+		return -1;
+
+	parse_rtattr_nested(tb, CTRL_ATTR_OP_MAX, arg);
+	if (tb[CTRL_ATTR_OP_ID]) {
+		__u32 *id = RTA_DATA(tb[CTRL_ATTR_OP_ID]);
+		fprintf(fp, " ID-0x%x ",*id);
+	}
+	/* we are only gonna do this for newer version of the controller */
+	if (tb[CTRL_ATTR_OP_FLAGS] && ctrl_ver >= 0x2) {
+		__u32 *fl = RTA_DATA(tb[CTRL_ATTR_OP_FLAGS]);
+		print_ctrl_cmd_flags(fp, *fl);
+	}
+	return 0;
+
+}
+
+static int print_ctrl_grp(FILE *fp, struct rtattr *arg, __u32 ctrl_ver)
+{
+	struct rtattr *tb[CTRL_ATTR_MCAST_GRP_MAX + 1];
+
+	if (arg == NULL)
+		return -1;
+
+	parse_rtattr_nested(tb, CTRL_ATTR_MCAST_GRP_MAX, arg);
+	if (tb[2]) {
+		__u32 *id = RTA_DATA(tb[CTRL_ATTR_MCAST_GRP_ID]);
+		fprintf(fp, " ID-0x%x ",*id);
+	}
+	if (tb[1]) {
+		char *name = RTA_DATA(tb[CTRL_ATTR_MCAST_GRP_NAME]);
+		fprintf(fp, " name: %s ", name);
+	}
+	return 0;
+
+}
+
+/*
+ * The controller sends one nlmsg per family
+*/
+static int print_ctrl(const struct sockaddr_nl *who,
+		      struct rtnl_ctrl_data *ctrl,
+		      struct nlmsghdr *n, void *arg)
+{
+	struct rtattr *tb[CTRL_ATTR_MAX + 1];
+	struct genlmsghdr *ghdr = NLMSG_DATA(n);
+	int len = n->nlmsg_len;
+	struct rtattr *attrs;
+	FILE *fp = (FILE *) arg;
+	__u32 ctrl_v = 0x1;
+
+	if (n->nlmsg_type !=  GENL_ID_CTRL) {
+		fprintf(stderr, "Not a controller message, nlmsg_len=%d "
+			"nlmsg_type=0x%x\n", n->nlmsg_len, n->nlmsg_type);
+		return 0;
+	}
+
+	if (ghdr->cmd != CTRL_CMD_GETFAMILY &&
+	    ghdr->cmd != CTRL_CMD_DELFAMILY &&
+	    ghdr->cmd != CTRL_CMD_NEWFAMILY &&
+	    ghdr->cmd != CTRL_CMD_NEWMCAST_GRP &&
+	    ghdr->cmd != CTRL_CMD_DELMCAST_GRP) {
+		fprintf(stderr, "Unknown controller command %d\n", ghdr->cmd);
+		return 0;
+	}
+
+	len -= NLMSG_LENGTH(GENL_HDRLEN);
+
+	if (len < 0) {
+		fprintf(stderr, "wrong controller message len %d\n", len);
+		return -1;
+	}
+
+	attrs = (struct rtattr *) ((char *) ghdr + GENL_HDRLEN);
+	parse_rtattr(tb, CTRL_ATTR_MAX, attrs, len);
+
+	if (tb[CTRL_ATTR_FAMILY_NAME]) {
+		char *name = RTA_DATA(tb[CTRL_ATTR_FAMILY_NAME]);
+		fprintf(fp, "\nName: %s\n",name);
+	}
+	if (tb[CTRL_ATTR_FAMILY_ID]) {
+		__u16 *id = RTA_DATA(tb[CTRL_ATTR_FAMILY_ID]);
+		fprintf(fp, "\tID: 0x%x ",*id);
+	}
+	if (tb[CTRL_ATTR_VERSION]) {
+		__u32 *v = RTA_DATA(tb[CTRL_ATTR_VERSION]);
+		fprintf(fp, " Version: 0x%x ",*v);
+		ctrl_v = *v;
+	}
+	if (tb[CTRL_ATTR_HDRSIZE]) {
+		__u32 *h = RTA_DATA(tb[CTRL_ATTR_HDRSIZE]);
+		fprintf(fp, " header size: %d ",*h);
+	}
+	if (tb[CTRL_ATTR_MAXATTR]) {
+		__u32 *ma = RTA_DATA(tb[CTRL_ATTR_MAXATTR]);
+		fprintf(fp, " max attribs: %d ",*ma);
+	}
+	/* end of family definitions .. */
+	fprintf(fp,"\n");
+	if (tb[CTRL_ATTR_OPS]) {
+		struct rtattr *tb2[GENL_MAX_FAM_OPS];
+		int i=0;
+		parse_rtattr_nested(tb2, GENL_MAX_FAM_OPS, tb[CTRL_ATTR_OPS]);
+		fprintf(fp, "\tcommands supported: \n");
+		for (i = 0; i < GENL_MAX_FAM_OPS; i++) {
+			if (tb2[i]) {
+				fprintf(fp, "\t\t#%d: ", i);
+				if (0 > print_ctrl_cmds(fp, tb2[i], ctrl_v)) {
+					fprintf(fp, "Error printing command\n");
+				}
+				/* for next command */
+				fprintf(fp,"\n");
+			}
+		}
+
+		/* end of family::cmds definitions .. */
+		fprintf(fp,"\n");
+	}
+
+	if (tb[CTRL_ATTR_MCAST_GROUPS]) {
+		struct rtattr *tb2[GENL_MAX_FAM_GRPS + 1];
+		int i;
+
+		parse_rtattr_nested(tb2, GENL_MAX_FAM_GRPS,
+				    tb[CTRL_ATTR_MCAST_GROUPS]);
+		fprintf(fp, "\tmulticast groups:\n");
+
+		for (i = 0; i < GENL_MAX_FAM_GRPS; i++) {
+			if (tb2[i]) {
+				fprintf(fp, "\t\t#%d: ", i);
+				if (0 > print_ctrl_grp(fp, tb2[i], ctrl_v))
+					fprintf(fp, "Error printing group\n");
+				/* for next group */
+				fprintf(fp,"\n");
+			}
+		}
+
+		/* end of family::groups definitions .. */
+		fprintf(fp,"\n");
+	}
+
+	fflush(fp);
+	return 0;
+}
+
+static int print_ctrl2(const struct sockaddr_nl *who,
+		      struct nlmsghdr *n, void *arg)
+{
+	return print_ctrl(who, NULL, n, arg);
+}
+
+static int ctrl_list(int cmd, int argc, char **argv)
+{
+	struct rtnl_handle rth;
+	struct nlmsghdr *nlh;
+	struct genlmsghdr *ghdr;
+	int ret = -1;
+	char d[GENL_NAMSIZ];
+	struct {
+		struct nlmsghdr         n;
+		char                    buf[4096];
+	} req;
+
+	memset(&req, 0, sizeof(req));
+
+	nlh = &req.n;
+	nlh->nlmsg_len = NLMSG_LENGTH(GENL_HDRLEN);
+	nlh->nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK;
+	nlh->nlmsg_type = GENL_ID_CTRL;
+
+	ghdr = NLMSG_DATA(&req.n);
+	ghdr->cmd = CTRL_CMD_GETFAMILY;
+
+	if (rtnl_open_byproto(&rth, 0, NETLINK_GENERIC) < 0) {
+		fprintf(stderr, "Cannot open generic netlink socket\n");
+		exit(1);
+	}
+
+	if (cmd == CTRL_CMD_GETFAMILY) {
+		if (argc != 2) {
+			fprintf(stderr, "Wrong number of params\n");
+			return -1;
+		}
+
+		if (matches(*argv, "name") == 0) {
+			NEXT_ARG();
+			strncpy(d, *argv, sizeof (d) - 1);
+			addattr_l(nlh, 128, CTRL_ATTR_FAMILY_NAME,
+				  d, strlen(d) + 1);
+		} else if (matches(*argv, "id") == 0) {
+			__u16 id;
+			NEXT_ARG();
+			if (get_u16(&id, *argv, 0)) {
+				fprintf(stderr, "Illegal \"id\"\n");
+				goto ctrl_done;
+			}
+
+			addattr_l(nlh, 128, CTRL_ATTR_FAMILY_ID, &id, 2);
+
+		} else {
+			fprintf(stderr, "Wrong params\n");
+			goto ctrl_done;
+		}
+
+		if (rtnl_talk(&rth, nlh, nlh, sizeof(req)) < 0) {
+			fprintf(stderr, "Error talking to the kernel\n");
+			goto ctrl_done;
+		}
+
+		if (print_ctrl2(NULL, nlh, (void *) stdout) < 0) {
+			fprintf(stderr, "Dump terminated\n");
+			goto ctrl_done;
+		}
+
+	}
+
+	if (cmd == CTRL_CMD_UNSPEC) {
+		nlh->nlmsg_flags = NLM_F_ROOT|NLM_F_MATCH|NLM_F_REQUEST;
+		nlh->nlmsg_seq = rth.dump = ++rth.seq;
+
+		if (rtnl_send(&rth, nlh, nlh->nlmsg_len) < 0) {
+			perror("Failed to send dump request\n");
+			goto ctrl_done;
+		}
+
+		rtnl_dump_filter(&rth, print_ctrl2, stdout);
+
+        }
+
+	ret = 0;
+ctrl_done:
+	rtnl_close(&rth);
+	return ret;
+}
+
+static int ctrl_listen(int argc, char **argv)
+{
+	struct rtnl_handle rth;
+
+	if (rtnl_open_byproto(&rth, nl_mgrp(GENL_ID_CTRL), NETLINK_GENERIC) < 0) {
+		fprintf(stderr, "Canot open generic netlink socket\n");
+		return -1;
+	}
+
+	if (rtnl_listen(&rth, print_ctrl, (void *) stdout) < 0)
+		return -1;
+
+	return 0;
+}
+
+static int parse_ctrl(struct genl_util *a, int argc, char **argv)
+{
+	argv++;
+	if (--argc <= 0) {
+		fprintf(stderr, "wrong controller params\n");
+		return -1;
+	}
+
+	if (matches(*argv, "monitor") == 0)
+		return ctrl_listen(argc-1, argv+1);
+	if (matches(*argv, "get") == 0)
+		return ctrl_list(CTRL_CMD_GETFAMILY, argc-1, argv+1);
+	if (matches(*argv, "list") == 0 ||
+	    matches(*argv, "show") == 0 ||
+	    matches(*argv, "lst") == 0)
+		return ctrl_list(CTRL_CMD_UNSPEC, argc-1, argv+1);
+	if (matches(*argv, "help") == 0)
+		return usage();
+
+	fprintf(stderr, "ctrl command \"%s\" is unknown, try \"ctrl help\".\n",
+		*argv);
+
+	return -1;
+}
+
+struct genl_util ctrl_genl_util = {
+	.name = "ctrl",
+	.parse_genlopt = parse_ctrl,
+	.print_genlopt = print_ctrl2,
+};
diff --git a/iproute2/genl/genl.c b/iproute2/genl/genl.c
new file mode 100644
index 0000000..e33fafd
--- /dev/null
+++ b/iproute2/genl/genl.c
@@ -0,0 +1,149 @@
+/*
+ * genl.c		"genl" utility frontend.
+ *
+ *		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.
+ *
+ * Authors:	Jamal Hadi Salim
+ *
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <syslog.h>
+#include <fcntl.h>
+#include <dlfcn.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <string.h>
+#include <errno.h>
+#include <linux/netlink.h>
+#include <linux/rtnetlink.h> /* until we put our own header */
+#include "SNAPSHOT.h"
+#include "utils.h"
+#include "genl_utils.h"
+
+int show_stats = 0;
+int show_details = 0;
+int show_raw = 0;
+int resolve_hosts = 0;
+
+static void *BODY;
+static struct genl_util * genl_list;
+
+
+static int print_nofopt(const struct sockaddr_nl *who, struct nlmsghdr *n,
+			void *arg)
+{
+	fprintf((FILE *) arg, "unknown genl type ..\n");
+	return 0;
+}
+
+static int parse_nofopt(struct genl_util *f, int argc, char **argv)
+{
+	if (argc) {
+		fprintf(stderr, "Unknown genl \"%s\", hence option \"%s\" "
+			"is unparsable\n", f->name, *argv);
+		return -1;
+	}
+
+	return 0;
+}
+
+static struct genl_util *get_genl_kind(const char *str)
+{
+	void *dlh;
+	char buf[256];
+	struct genl_util *f;
+
+	for (f = genl_list; f; f = f->next)
+		if (strcmp(f->name, str) == 0)
+			return f;
+
+	snprintf(buf, sizeof(buf), "%s.so", str);
+	dlh = dlopen(buf, RTLD_LAZY);
+	if (dlh == NULL) {
+		dlh = BODY;
+		if (dlh == NULL) {
+			dlh = BODY = dlopen(NULL, RTLD_LAZY);
+			if (dlh == NULL)
+				goto noexist;
+		}
+	}
+
+	snprintf(buf, sizeof(buf), "%s_genl_util", str);
+
+	f = dlsym(dlh, buf);
+	if (f == NULL)
+		goto noexist;
+reg:
+	f->next = genl_list;
+	genl_list = f;
+	return f;
+
+noexist:
+	f = malloc(sizeof(*f));
+	if (f) {
+		memset(f, 0, sizeof(*f));
+		strncpy(f->name, str, 15);
+		f->parse_genlopt = parse_nofopt;
+		f->print_genlopt = print_nofopt;
+		goto reg;
+	}
+	return f;
+}
+
+static void usage(void) __attribute__((noreturn));
+
+static void usage(void)
+{
+	fprintf(stderr, "Usage: genl [ OPTIONS ] OBJECT | help }\n"
+	                "where  OBJECT := { ctrl etc }\n"
+	                "       OPTIONS := { -s[tatistics] | -d[etails] | -r[aw] }\n");
+	exit(-1);
+}
+
+int main(int argc, char **argv)
+{
+	while (argc > 1) {
+		if (argv[1][0] != '-')
+			break;
+		if (matches(argv[1], "-stats") == 0 ||
+		    matches(argv[1], "-statistics") == 0) {
+			++show_stats;
+		} else if (matches(argv[1], "-details") == 0) {
+			++show_details;
+		} else if (matches(argv[1], "-raw") == 0) {
+			++show_raw;
+		} else if (matches(argv[1], "-Version") == 0) {
+			printf("genl utility, iproute2-ss%s\n", SNAPSHOT);
+			exit(0);
+		} else if (matches(argv[1], "-help") == 0) {
+			usage();
+		} else {
+			fprintf(stderr, "Option \"%s\" is unknown, try "
+				"\"genl -help\".\n", argv[1]);
+			exit(-1);
+		}
+		argc--;	argv++;
+	}
+
+	if (argc > 1) {
+		int ret;
+		struct genl_util *a = NULL;
+		a = get_genl_kind(argv[1]);
+		if (!a) {
+			fprintf(stderr,"bad genl %s\n", argv[1]);
+			exit(-1);
+		}
+
+		ret = a->parse_genlopt(a, argc-1, argv+1);
+		return ret;
+	}
+
+	usage();
+}
diff --git a/iproute2/genl/genl_utils.h b/iproute2/genl/genl_utils.h
new file mode 100644
index 0000000..85b5183
--- /dev/null
+++ b/iproute2/genl/genl_utils.h
@@ -0,0 +1,17 @@
+#ifndef _TC_UTIL_H_
+#define _TC_UTIL_H_ 1
+
+#include "utils.h"
+#include "linux/genetlink.h"
+
+struct genl_util
+{
+	struct  genl_util *next;
+	char	name[16];
+	int	(*parse_genlopt)(struct genl_util *fu, int argc, char **argv);
+	int	(*print_genlopt)(const struct sockaddr_nl *who, struct nlmsghdr *n, void *arg);
+};
+
+extern int genl_ctrl_resolve_family(const char *family);
+
+#endif
diff --git a/iproute2/genl/static-syms.c b/iproute2/genl/static-syms.c
new file mode 100644
index 0000000..0bc8074
--- /dev/null
+++ b/iproute2/genl/static-syms.c
@@ -0,0 +1,14 @@
+/*
+ * This file creates a dummy version of dynamic loading
+ * for environments where dynamic linking
+ * is not used or available.
+ */
+
+#include <string.h>
+#include "dlfcn.h"
+
+void *_dlsym(const char *sym)
+{
+#include "static-syms.h"
+	return NULL;
+}
diff --git a/iproute2/include/SNAPSHOT.h b/iproute2/include/SNAPSHOT.h
new file mode 100644
index 0000000..58d3632
--- /dev/null
+++ b/iproute2/include/SNAPSHOT.h
@@ -0,0 +1 @@
+static const char SNAPSHOT[] = "160111";
diff --git a/iproute2/include/bpf_api.h b/iproute2/include/bpf_api.h
new file mode 100644
index 0000000..0666a31
--- /dev/null
+++ b/iproute2/include/bpf_api.h
@@ -0,0 +1,225 @@
+#ifndef __BPF_API__
+#define __BPF_API__
+
+/* Note:
+ *
+ * This file can be included into eBPF kernel programs. It contains
+ * a couple of useful helper functions, map/section ABI (bpf_elf.h),
+ * misc macros and some eBPF specific LLVM built-ins.
+ */
+
+#include <stdint.h>
+
+#include <linux/pkt_cls.h>
+#include <linux/bpf.h>
+#include <linux/filter.h>
+
+#include <asm/byteorder.h>
+
+#include "bpf_elf.h"
+
+/** Misc macros. */
+
+#ifndef __stringify
+# define __stringify(X)		#X
+#endif
+
+#ifndef __maybe_unused
+# define __maybe_unused		__attribute__((__unused__))
+#endif
+
+#ifndef offsetof
+# define offsetof(TYPE, MEMBER)	__builtin_offsetof(TYPE, MEMBER)
+#endif
+
+#ifndef likely
+# define likely(X)		__builtin_expect(!!(X), 1)
+#endif
+
+#ifndef unlikely
+# define unlikely(X)		__builtin_expect(!!(X), 0)
+#endif
+
+#ifndef htons
+# define htons(X)		__constant_htons((X))
+#endif
+
+#ifndef ntohs
+# define ntohs(X)		__constant_ntohs((X))
+#endif
+
+#ifndef htonl
+# define htonl(X)		__constant_htonl((X))
+#endif
+
+#ifndef ntohl
+# define ntohl(X)		__constant_ntohl((X))
+#endif
+
+/** Section helper macros. */
+
+#ifndef __section
+# define __section(NAME)						\
+	__attribute__((section(NAME), used))
+#endif
+
+#ifndef __section_tail
+# define __section_tail(ID, KEY)					\
+	__section(__stringify(ID) "/" __stringify(KEY))
+#endif
+
+#ifndef __section_cls_entry
+# define __section_cls_entry						\
+	__section(ELF_SECTION_CLASSIFIER)
+#endif
+
+#ifndef __section_act_entry
+# define __section_act_entry						\
+	__section(ELF_SECTION_ACTION)
+#endif
+
+#ifndef __section_license
+# define __section_license						\
+	__section(ELF_SECTION_LICENSE)
+#endif
+
+#ifndef __section_maps
+# define __section_maps							\
+	__section(ELF_SECTION_MAPS)
+#endif
+
+/** Declaration helper macros. */
+
+#ifndef BPF_LICENSE
+# define BPF_LICENSE(NAME)						\
+	char ____license[] __section_license = NAME
+#endif
+
+#ifndef __BPF_MAP
+# define __BPF_MAP(NAME, TYPE, ID, SIZE_KEY, SIZE_VALUE, PIN, MAX_ELEM)	\
+	struct bpf_elf_map __section_maps NAME = {			\
+		.type		= (TYPE),				\
+		.id		= (ID),					\
+		.size_key	= (SIZE_KEY),				\
+		.size_value	= (SIZE_VALUE),				\
+		.pinning	= (PIN),				\
+		.max_elem	= (MAX_ELEM),				\
+	}
+#endif
+
+#ifndef BPF_HASH
+# define BPF_HASH(NAME, ID, SIZE_KEY, SIZE_VALUE, PIN, MAX_ELEM)	\
+	__BPF_MAP(NAME, BPF_MAP_TYPE_HASH, ID, SIZE_KEY, SIZE_VALUE,	\
+		  PIN, MAX_ELEM)
+#endif
+
+#ifndef BPF_ARRAY
+# define BPF_ARRAY(NAME, ID, SIZE_VALUE, PIN, MAX_ELEM)			\
+	__BPF_MAP(NAME, BPF_MAP_TYPE_ARRAY, ID, sizeof(uint32_t), 	\
+		  SIZE_VALUE, PIN, MAX_ELEM)
+#endif
+
+#ifndef BPF_ARRAY2
+# define BPF_ARRAY2(NAME, ID, PIN, MAX_ELEM)				\
+	BPF_ARRAY(NAME, ID, sizeof(uint16_t), PIN, MAX_ELEM)
+#endif
+
+#ifndef BPF_ARRAY4
+# define BPF_ARRAY4(NAME, ID, PIN, MAX_ELEM)				\
+	BPF_ARRAY(NAME, ID, sizeof(uint32_t), PIN, MAX_ELEM)
+#endif
+
+#ifndef BPF_ARRAY8
+# define BPF_ARRAY8(NAME, ID, PIN, MAX_ELEM)				\
+	BPF_ARRAY(NAME, ID, sizeof(uint64_t), PIN, MAX_ELEM)
+#endif
+
+#ifndef BPF_PROG_ARRAY
+# define BPF_PROG_ARRAY(NAME, ID, PIN, MAX_ELEM)			\
+	__BPF_MAP(NAME, BPF_MAP_TYPE_PROG_ARRAY, ID, sizeof(uint32_t),	\
+		  sizeof(uint32_t), PIN, MAX_ELEM)
+#endif
+
+/** Classifier helper */
+
+#ifndef BPF_H_DEFAULT
+# define BPF_H_DEFAULT	-1
+#endif
+
+/** BPF helper functions for tc. */
+
+#ifndef BPF_FUNC
+# define BPF_FUNC(NAME, ...)						\
+	(* NAME)(__VA_ARGS__) __maybe_unused = (void *) BPF_FUNC_##NAME
+#endif
+
+/* Map access/manipulation */
+static void *BPF_FUNC(map_lookup_elem, void *map, const void *key);
+static int BPF_FUNC(map_update_elem, void *map, const void *key,
+		    const void *value, uint32_t flags);
+static int BPF_FUNC(map_delete_elem, void *map, const void *key);
+
+/* Time access */
+static uint64_t BPF_FUNC(ktime_get_ns);
+
+/* Debugging */
+static void BPF_FUNC(trace_printk, const char *fmt, int fmt_size, ...);
+
+/* Random numbers */
+static uint32_t BPF_FUNC(get_prandom_u32);
+
+/* Tail calls */
+static void BPF_FUNC(tail_call, struct __sk_buff *skb, void *map,
+		     uint32_t index);
+
+/* System helpers */
+static uint32_t BPF_FUNC(get_smp_processor_id);
+
+/* Packet misc meta data */
+static uint32_t BPF_FUNC(get_cgroup_classid, struct __sk_buff *skb);
+static uint32_t BPF_FUNC(get_route_realm, struct __sk_buff *skb);
+
+/* Packet redirection */
+static int BPF_FUNC(redirect, int ifindex, uint32_t flags);
+static int BPF_FUNC(clone_redirect, struct __sk_buff *skb, int ifindex,
+		    uint32_t flags);
+
+/* Packet manipulation */
+#define BPF_PSEUDO_HDR			0x10
+#define BPF_HAS_PSEUDO_HDR(flags)	((flags) & BPF_PSEUDO_HDR)
+#define BPF_HDR_FIELD_SIZE(flags)	((flags) & 0x0f)
+
+static int BPF_FUNC(skb_store_bytes, struct __sk_buff *skb, uint32_t off,
+		    void *from, uint32_t len, uint32_t flags);
+static int BPF_FUNC(l3_csum_replace, struct __sk_buff *skb, uint32_t off,
+		    uint32_t from, uint32_t to, uint32_t flags);
+static int BPF_FUNC(l4_csum_replace, struct __sk_buff *skb, uint32_t off,
+		    uint32_t from, uint32_t to, uint32_t flags);
+
+/* Packet vlan encap/decap */
+static int BPF_FUNC(skb_vlan_push, struct __sk_buff *skb, uint16_t proto,
+		    uint16_t vlan_tci);
+static int BPF_FUNC(skb_vlan_pop, struct __sk_buff *skb);
+
+/* Packet tunnel encap/decap */
+static int BPF_FUNC(skb_get_tunnel_key, struct __sk_buff *skb,
+		    struct bpf_tunnel_key *to, uint32_t size, uint32_t flags);
+static int BPF_FUNC(skb_set_tunnel_key, struct __sk_buff *skb,
+		    struct bpf_tunnel_key *from, uint32_t size, uint32_t flags);
+
+/** LLVM built-ins */
+
+#ifndef lock_xadd
+# define lock_xadd(ptr, val)	((void) __sync_fetch_and_add(ptr, val))
+#endif
+
+unsigned long long load_byte(void *skb, unsigned long long off)
+	asm ("llvm.bpf.load.byte");
+
+unsigned long long load_half(void *skb, unsigned long long off)
+	asm ("llvm.bpf.load.half");
+
+unsigned long long load_word(void *skb, unsigned long long off)
+	asm ("llvm.bpf.load.word");
+
+#endif /* __BPF_API__ */
diff --git a/iproute2/include/bpf_elf.h b/iproute2/include/bpf_elf.h
new file mode 100644
index 0000000..31a8974
--- /dev/null
+++ b/iproute2/include/bpf_elf.h
@@ -0,0 +1,39 @@
+#ifndef __BPF_ELF__
+#define __BPF_ELF__
+
+#include <asm/types.h>
+
+/* Note:
+ *
+ * Below ELF section names and bpf_elf_map structure definition
+ * are not (!) kernel ABI. It's rather a "contract" between the
+ * application and the BPF loader in tc. For compatibility, the
+ * section names should stay as-is. Introduction of aliases, if
+ * needed, are a possibility, though.
+ */
+
+/* ELF section names, etc */
+#define ELF_SECTION_LICENSE	"license"
+#define ELF_SECTION_MAPS	"maps"
+#define ELF_SECTION_CLASSIFIER	"classifier"
+#define ELF_SECTION_ACTION	"action"
+
+#define ELF_MAX_MAPS		64
+#define ELF_MAX_LICENSE_LEN	128
+
+/* Object pinning settings */
+#define PIN_NONE		0
+#define PIN_OBJECT_NS		1
+#define PIN_GLOBAL_NS		2
+
+/* ELF map definition */
+struct bpf_elf_map {
+	__u32 type;
+	__u32 size_key;
+	__u32 size_value;
+	__u32 max_elem;
+	__u32 id;
+	__u32 pinning;
+};
+
+#endif /* __BPF_ELF__ */
diff --git a/iproute2/include/bpf_scm.h b/iproute2/include/bpf_scm.h
new file mode 100644
index 0000000..35117d1
--- /dev/null
+++ b/iproute2/include/bpf_scm.h
@@ -0,0 +1,75 @@
+#ifndef __BPF_SCM__
+#define __BPF_SCM__
+
+#include <sys/types.h>
+#include <sys/socket.h>
+
+#include "utils.h"
+#include "bpf_elf.h"
+
+#define BPF_SCM_AUX_VER		1
+#define BPF_SCM_MAX_FDS		ELF_MAX_MAPS
+#define BPF_SCM_MSG_SIZE	1024
+
+struct bpf_elf_st {
+	dev_t st_dev;
+	ino_t st_ino;
+};
+
+struct bpf_map_aux {
+	unsigned short uds_ver;
+	unsigned short num_ent;
+	char obj_name[64];
+	struct bpf_elf_st obj_st;
+	struct bpf_elf_map ent[BPF_SCM_MAX_FDS];
+};
+
+struct bpf_map_set_msg {
+	struct msghdr hdr;
+	struct iovec iov;
+	char msg_buf[BPF_SCM_MSG_SIZE];
+	struct bpf_map_aux aux;
+};
+
+static inline int *bpf_map_set_init(struct bpf_map_set_msg *msg,
+				    struct sockaddr_un *addr,
+				    unsigned int addr_len)
+{
+	const unsigned int cmsg_ctl_len = sizeof(int) * BPF_SCM_MAX_FDS;
+	struct cmsghdr *cmsg;
+
+	msg->iov.iov_base = &msg->aux;
+	msg->iov.iov_len = sizeof(msg->aux);
+
+	msg->hdr.msg_iov = &msg->iov;
+	msg->hdr.msg_iovlen = 1;
+
+	msg->hdr.msg_name = (struct sockaddr *)addr;
+	msg->hdr.msg_namelen = addr_len;
+
+	BUILD_BUG_ON(sizeof(msg->msg_buf) < cmsg_ctl_len);
+	msg->hdr.msg_control = &msg->msg_buf;
+	msg->hdr.msg_controllen	= cmsg_ctl_len;
+
+	cmsg = CMSG_FIRSTHDR(&msg->hdr);
+	cmsg->cmsg_len = msg->hdr.msg_controllen;
+	cmsg->cmsg_level = SOL_SOCKET;
+	cmsg->cmsg_type	= SCM_RIGHTS;
+
+	return (int *)CMSG_DATA(cmsg);
+}
+
+static inline void bpf_map_set_init_single(struct bpf_map_set_msg *msg,
+					   int num)
+{
+	struct cmsghdr *cmsg;
+
+	msg->hdr.msg_controllen = CMSG_LEN(sizeof(int) * num);
+	msg->iov.iov_len = offsetof(struct bpf_map_aux, ent) +
+			   sizeof(struct bpf_elf_map) * num;
+
+	cmsg = CMSG_FIRSTHDR(&msg->hdr);
+	cmsg->cmsg_len = msg->hdr.msg_controllen;
+}
+
+#endif /* __BPF_SCM__ */
diff --git a/iproute2/include/color.h b/iproute2/include/color.h
new file mode 100644
index 0000000..b85003a
--- /dev/null
+++ b/iproute2/include/color.h
@@ -0,0 +1,16 @@
+#ifndef __COLOR_H__
+#define __COLOR_H__ 1
+
+enum color_attr {
+	COLOR_IFNAME,
+	COLOR_MAC,
+	COLOR_INET,
+	COLOR_INET6,
+	COLOR_OPERSTATE_UP,
+	COLOR_OPERSTATE_DOWN
+};
+
+void enable_color(void);
+int color_fprintf(FILE *fp, enum color_attr attr, const char *fmt, ...);
+
+#endif
diff --git a/iproute2/include/dlfcn.h b/iproute2/include/dlfcn.h
new file mode 100644
index 0000000..f15bc2c
--- /dev/null
+++ b/iproute2/include/dlfcn.h
@@ -0,0 +1,40 @@
+/*
+ * Stub dlfcn implementation for systems that lack shared library support
+ * but obviously can still reference compiled-in symbols.
+ */
+
+#ifndef NO_SHARED_LIBS
+#include_next <dlfcn.h>
+#else
+
+#define RTLD_LAZY 0
+#define RTLD_GLOBAL 1
+#define _FAKE_DLFCN_HDL (void *)0xbeefcafe
+
+static inline void *dlopen(const char *file, int flag)
+{
+	if (file == NULL)
+		return _FAKE_DLFCN_HDL;
+	else
+		return NULL;
+}
+
+void *_dlsym(const char *sym);
+static inline void *dlsym(void *handle, const char *sym)
+{
+	if (handle != _FAKE_DLFCN_HDL)
+		return NULL;
+	return _dlsym(sym);
+}
+
+static inline char *dlerror(void)
+{
+	return NULL;
+}
+
+static inline int dlclose(void *handle)
+{
+	return (handle == _FAKE_DLFCN_HDL) ? 0 : 1;
+}
+
+#endif
diff --git a/iproute2/include/hlist.h b/iproute2/include/hlist.h
new file mode 100644
index 0000000..4e8de9e
--- /dev/null
+++ b/iproute2/include/hlist.h
@@ -0,0 +1,56 @@
+#ifndef __HLIST_H__
+#define __HLIST_H__ 1
+/* Hash list stuff from kernel */
+
+#include <stddef.h>
+
+#define container_of(ptr, type, member) ({			\
+	const typeof( ((type *)0)->member ) *__mptr = (ptr);	\
+	(type *)( (char *)__mptr - offsetof(type,member) );})
+
+struct hlist_head {
+	struct hlist_node *first;
+};
+
+struct hlist_node {
+	struct hlist_node *next, **pprev;
+};
+
+static inline void hlist_del(struct hlist_node *n)
+{
+	struct hlist_node *next = n->next;
+	struct hlist_node **pprev = n->pprev;
+	*pprev = next;
+	if (next)
+		next->pprev = pprev;
+}
+
+static inline void hlist_add_head(struct hlist_node *n, struct hlist_head *h)
+{
+	struct hlist_node *first = h->first;
+	n->next = first;
+	if (first)
+		first->pprev = &n->next;
+	h->first = n;
+	n->pprev = &h->first;
+}
+
+#define hlist_for_each(pos, head) \
+	for (pos = (head)->first; pos ; pos = pos->next)
+
+
+#define hlist_for_each_safe(pos, n, head) \
+	for (pos = (head)->first; pos && ({ n = pos->next; 1; }); \
+	     pos = n)
+
+#define hlist_entry_safe(ptr, type, member) \
+	({ typeof(ptr) ____ptr = (ptr); \
+	   ____ptr ? hlist_entry(____ptr, type, member) : NULL; \
+	})
+
+#define hlist_for_each_entry(pos, head, member)				\
+	for (pos = hlist_entry_safe((head)->first, typeof(*(pos)), member);\
+	     pos;							\
+	     pos = hlist_entry_safe((pos)->member.next, typeof(*(pos)), member))
+
+#endif /* __HLIST_H__ */
diff --git a/iproute2/include/ip6tables.h b/iproute2/include/ip6tables.h
new file mode 100644
index 0000000..5f1c5b6
--- /dev/null
+++ b/iproute2/include/ip6tables.h
@@ -0,0 +1,20 @@
+#ifndef _IP6TABLES_USER_H
+#define _IP6TABLES_USER_H
+
+#include <netinet/ip.h>
+#include <xtables.h>
+#include <libiptc/libip6tc.h>
+#include <iptables/internal.h>
+
+/* Your shared library should call one of these. */
+extern int do_command6(int argc, char *argv[], char **table,
+		       struct xtc_handle **handle, bool restore);
+
+extern int for_each_chain6(int (*fn)(const xt_chainlabel, int, struct xtc_handle *), int verbose, int builtinstoo, struct xtc_handle *handle);
+extern int flush_entries6(const xt_chainlabel chain, int verbose, struct xtc_handle *handle);
+extern int delete_chain6(const xt_chainlabel chain, int verbose, struct xtc_handle *handle);
+void print_rule6(const struct ip6t_entry *e, struct xtc_handle *h, const char *chain, int counters);
+
+extern struct xtables_globals ip6tables_globals;
+
+#endif /*_IP6TABLES_USER_H*/
diff --git a/iproute2/include/iptables.h b/iproute2/include/iptables.h
new file mode 100644
index 0000000..78c10ab
--- /dev/null
+++ b/iproute2/include/iptables.h
@@ -0,0 +1,25 @@
+#ifndef _IPTABLES_USER_H
+#define _IPTABLES_USER_H
+
+#include <netinet/ip.h>
+#include <xtables.h>
+#include <libiptc/libiptc.h>
+#include <iptables/internal.h>
+
+/* Your shared library should call one of these. */
+extern int do_command4(int argc, char *argv[], char **table,
+		      struct xtc_handle **handle, bool restore);
+extern int delete_chain4(const xt_chainlabel chain, int verbose,
+			struct xtc_handle *handle);
+extern int flush_entries4(const xt_chainlabel chain, int verbose, 
+			struct xtc_handle *handle);
+extern int for_each_chain4(int (*fn)(const xt_chainlabel, int, struct xtc_handle *),
+		int verbose, int builtinstoo, struct xtc_handle *handle);
+extern void print_rule4(const struct ipt_entry *e,
+		struct xtc_handle *handle, const char *chain, int counters);
+
+extern struct xtables_globals iptables_globals;
+
+extern struct xtables_globals xtables_globals;
+
+#endif /*_IPTABLES_USER_H*/
diff --git a/iproute2/include/iptables/internal.h b/iproute2/include/iptables/internal.h
new file mode 100644
index 0000000..62a8ecb
--- /dev/null
+++ b/iproute2/include/iptables/internal.h
@@ -0,0 +1,13 @@
+#ifndef IPTABLES_INTERNAL_H
+#define IPTABLES_INTERNAL_H 1
+
+#define IPTABLES_VERSION "1.6.0"
+
+/**
+ * Program's own name and version.
+ */
+extern const char *program_name, *program_version;
+
+extern int line;
+
+#endif /* IPTABLES_INTERNAL_H */
diff --git a/iproute2/include/iptables_common.h b/iproute2/include/iptables_common.h
new file mode 100644
index 0000000..9099667
--- /dev/null
+++ b/iproute2/include/iptables_common.h
@@ -0,0 +1,51 @@
+#ifndef _IPTABLES_COMMON_H
+#define _IPTABLES_COMMON_H
+/* Shared definitions between ipv4 and ipv6. */
+
+enum exittype {
+	OTHER_PROBLEM = 1,
+	PARAMETER_PROBLEM,
+	VERSION_PROBLEM,
+	RESOURCE_PROBLEM
+};
+
+/* this is a special 64bit data type that is 8-byte aligned */
+#define aligned_u64 unsigned long long __attribute__((aligned(8)))
+
+extern void exit_printhelp(void) __attribute__((noreturn));
+extern void exit_tryhelp(int) __attribute__((noreturn));
+int check_inverse(const char option[], int *invert, int *optind, int argc);
+extern int string_to_number(const char *, 
+			    unsigned int, 
+			    unsigned int,
+			    unsigned int *);
+extern int string_to_number_l(const char *, 
+			    unsigned long int, 
+			    unsigned long int,
+			    unsigned long *);
+extern int string_to_number_ll(const char *, 
+			    unsigned long long int, 
+			    unsigned long long int,
+			    unsigned long long *);
+extern int iptables_insmod(const char *modname, const char *modprobe);
+extern int load_iptables_ko(const char *modprobe);
+void exit_error(enum exittype, char *, ...)__attribute__((noreturn,
+							  format(printf,2,3)));
+extern const char *program_name, *program_version;
+extern char *lib_dir;
+
+#define _init __attribute__((constructor)) my_init
+#ifdef NO_SHARED_LIBS
+# ifdef _INIT
+#  undef _init
+#  define _init _INIT
+# endif
+  extern void init_extensions(void);
+#endif
+
+#define __be32	u_int32_t
+#define __le32	u_int32_t
+#define __be16	u_int16_t
+#define __le16	u_int16_t
+
+#endif /*_IPTABLES_COMMON_H*/
diff --git a/iproute2/include/json_writer.h b/iproute2/include/json_writer.h
new file mode 100644
index 0000000..ab9a008
--- /dev/null
+++ b/iproute2/include/json_writer.h
@@ -0,0 +1,61 @@
+/*
+ * Simple streaming JSON writer
+ *
+ * This takes care of the annoying bits of JSON syntax like the commas
+ * after elements
+ *
+ * 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.
+ *
+ * Authors:	Stephen Hemminger <stephen@networkplumber.org>
+ */
+
+#ifndef _JSON_WRITER_H_
+#define _JSON_WRITER_H_
+
+#include <stdbool.h>
+#include <stdint.h>
+
+/* Opaque class structure */
+typedef struct json_writer json_writer_t;
+
+/* Create a new JSON stream */
+json_writer_t *jsonw_new(FILE *f);
+/* End output to JSON stream */
+void jsonw_destroy(json_writer_t **self_p);
+
+/* Cause output to have pretty whitespace */
+void jsonw_pretty(json_writer_t *self, bool on);
+
+/* Add property name */
+void jsonw_name(json_writer_t *self, const char *name);
+
+/* Add value  */
+void jsonw_string(json_writer_t *self, const char *value);
+void jsonw_bool(json_writer_t *self, bool value);
+void jsonw_float(json_writer_t *self, double number);
+void jsonw_uint(json_writer_t *self, uint64_t number);
+void jsonw_int(json_writer_t *self, int64_t number);
+void jsonw_null(json_writer_t *self);
+
+/* Useful Combinations of name and value */
+void jsonw_string_field(json_writer_t *self, const char *prop, const char *val);
+void jsonw_bool_field(json_writer_t *self, const char *prop, bool value);
+void jsonw_float_field(json_writer_t *self, const char *prop, double num);
+void jsonw_uint_field(json_writer_t *self, const char *prop, uint64_t num);
+void jsonw_int_field(json_writer_t *self, const char *prop, int64_t num);
+void jsonw_null_field(json_writer_t *self, const char *prop);
+
+/* Collections */
+void jsonw_start_object(json_writer_t *self);
+void jsonw_end_object(json_writer_t *self);
+
+void jsonw_start_array(json_writer_t *self);
+void jsonw_end_array(json_writer_t *self);
+
+/* Override default exception handling */
+typedef void (jsonw_err_handler_fn)(const char *);
+
+#endif /* _JSON_WRITER_H_ */
diff --git a/iproute2/include/libgenl.h b/iproute2/include/libgenl.h
new file mode 100644
index 0000000..9db4baf
--- /dev/null
+++ b/iproute2/include/libgenl.h
@@ -0,0 +1,25 @@
+#ifndef __LIBGENL_H__
+#define __LIBGENL_H__
+
+#include "libnetlink.h"
+
+#define GENL_REQUEST(_req, _bufsiz, _family, _hdrsiz, _ver, _cmd, _flags) \
+struct {								\
+	struct nlmsghdr		n;					\
+	struct genlmsghdr	g;					\
+	char			buf[NLMSG_ALIGN(_hdrsiz) + (_bufsiz)];	\
+} _req = {								\
+	.n = {								\
+		.nlmsg_type = (_family),				\
+		.nlmsg_flags = (_flags),				\
+		.nlmsg_len = NLMSG_LENGTH(GENL_HDRLEN + (_hdrsiz)),	\
+	},								\
+	.g = {								\
+		.cmd = (_cmd),						\
+		.version = (_ver),					\
+	},								\
+}
+
+extern int genl_resolve_family(struct rtnl_handle *grth, const char *family);
+
+#endif /* __LIBGENL_H__ */
diff --git a/iproute2/include/libiptc/ipt_kernel_headers.h b/iproute2/include/libiptc/ipt_kernel_headers.h
new file mode 100644
index 0000000..a5963e9
--- /dev/null
+++ b/iproute2/include/libiptc/ipt_kernel_headers.h
@@ -0,0 +1,15 @@
+/* This is the userspace/kernel interface for Generic IP Chains,
+   required for libc6. */
+#ifndef _FWCHAINS_KERNEL_HEADERS_H
+#define _FWCHAINS_KERNEL_HEADERS_H
+
+#include <limits.h>
+
+#include <netinet/ip.h>
+#include <netinet/in.h>
+#include <netinet/ip_icmp.h>
+#include <netinet/tcp.h>
+#include <netinet/udp.h>
+#include <net/if.h>
+#include <sys/types.h>
+#endif
diff --git a/iproute2/include/libiptc/libip6tc.h b/iproute2/include/libiptc/libip6tc.h
new file mode 100644
index 0000000..9aed80a
--- /dev/null
+++ b/iproute2/include/libiptc/libip6tc.h
@@ -0,0 +1,161 @@
+#ifndef _LIBIP6TC_H
+#define _LIBIP6TC_H
+/* Library which manipulates firewall rules. Version 0.2. */
+
+#include <linux/types.h>
+#include <libiptc/ipt_kernel_headers.h>
+#ifdef __cplusplus
+#	include <climits>
+#else
+#	include <limits.h> /* INT_MAX in ip6_tables.h */
+#endif
+#include <linux/netfilter_ipv6/ip6_tables.h>
+#include <libiptc/xtcshared.h>
+
+#define ip6tc_handle xtc_handle
+#define ip6t_chainlabel xt_chainlabel
+
+#define IP6TC_LABEL_ACCEPT "ACCEPT"
+#define IP6TC_LABEL_DROP "DROP"
+#define IP6TC_LABEL_QUEUE   "QUEUE"
+#define IP6TC_LABEL_RETURN "RETURN"
+
+/* Does this chain exist? */
+int ip6tc_is_chain(const char *chain, struct xtc_handle *const handle);
+
+/* Take a snapshot of the rules. Returns NULL on error. */
+struct xtc_handle *ip6tc_init(const char *tablename);
+
+/* Cleanup after ip6tc_init(). */
+void ip6tc_free(struct xtc_handle *h);
+
+/* Iterator functions to run through the chains.  Returns NULL at end. */
+const char *ip6tc_first_chain(struct xtc_handle *handle);
+const char *ip6tc_next_chain(struct xtc_handle *handle);
+
+/* Get first rule in the given chain: NULL for empty chain. */
+const struct ip6t_entry *ip6tc_first_rule(const char *chain,
+