]> git.proxmox.com Git - mirror_ifupdown2.git/commitdiff
move ifupdown2/* .
authorRoopa Prabhu <roopa@cumulusnetworks.com>
Sun, 2 Aug 2015 12:05:52 +0000 (05:05 -0700)
committerRoopa Prabhu <roopa@cumulusnetworks.com>
Sun, 2 Aug 2015 12:05:52 +0000 (05:05 -0700)
ifupdown2 code was one level deeper because ifupdown2 initially
had ifupdown2 and ifupdown2-addons as two separate packages.
Since they were combined into one package, it makes sense to
move all combined code under the top level directory

Signed-off-by: Roopa Prabhu <roopa@cumulusnetworks.com>
178 files changed:
KNOWN_ISSUES [new file with mode: 0644]
LICENSE [new file with mode: 0644]
README.rst [new file with mode: 0644]
TODO [new file with mode: 0644]
addons/address.py [new file with mode: 0644]
addons/addressvirtual.py [new file with mode: 0644]
addons/bridge.py [new file with mode: 0644]
addons/bridgevlan.py [new file with mode: 0644]
addons/dhcp.py [new file with mode: 0644]
addons/ethtool.py [new file with mode: 0644]
addons/ifenslave.py [new file with mode: 0644]
addons/loopback.py [new file with mode: 0644]
addons/mstpctl.py [new file with mode: 0644]
addons/usercmds.py [new file with mode: 0644]
addons/vlan.py [new file with mode: 0644]
addons/vrrpd.py [new file with mode: 0644]
addons/vxlan.py [new file with mode: 0644]
build.sh [new file with mode: 0755]
completion/ifup [new file with mode: 0644]
config/addons.conf [new file with mode: 0644]
config/ifupdown2.conf [new file with mode: 0644]
config/networking [new file with mode: 0644]
debian/copyright [new file with mode: 0644]
debian/python-ifupdown2.postinst [new file with mode: 0644]
debian/python-ifupdown2.postrm [new file with mode: 0644]
debian/python-ifupdown2.preinst [new file with mode: 0755]
docs/Makefile [new file with mode: 0644]
docs/examples/generate_interfaces.py [new file with mode: 0755]
docs/examples/interfaces [new file with mode: 0644]
docs/examples/interfaces_bridge_igmp_mstp [new file with mode: 0644]
docs/examples/interfaces_bridge_template_func [new file with mode: 0644]
docs/examples/interfaces_with_template [new file with mode: 0644]
docs/examples/vlan_aware_bridges/interfaces.basic [new file with mode: 0644]
docs/examples/vlan_aware_bridges/interfaces.vlan_prune_and_access_ports [new file with mode: 0644]
docs/examples/vlan_aware_bridges/interfaces.with_bonds [new file with mode: 0644]
docs/examples/vlan_aware_bridges/interfaces.with_clag [new file with mode: 0644]
docs/source/addonsapiref.rst [new file with mode: 0644]
docs/source/addonshelperapiref.rst [new file with mode: 0644]
docs/source/apiref.rst [new file with mode: 0644]
docs/source/conf.py [new file with mode: 0644]
docs/source/developmentcorner.rst [new file with mode: 0644]
docs/source/gettingstarted.rst [new file with mode: 0644]
docs/source/images/interfaces.png [new file with mode: 0644]
docs/source/images/interfaces_all.png [new file with mode: 0644]
docs/source/index.rst [new file with mode: 0644]
docs/source/intro.rst [new file with mode: 0644]
docs/source/userguide.rst [new file with mode: 0644]
ifupdown/__init__.py [new file with mode: 0644]
ifupdown/exceptions.py [new file with mode: 0644]
ifupdown/graph.py [new file with mode: 0644]
ifupdown/iface.py [new file with mode: 0644]
ifupdown/iff.py [new file with mode: 0644]
ifupdown/ifupdownbase.py [new file with mode: 0644]
ifupdown/ifupdownmain.py [new file with mode: 0644]
ifupdown/netlink.py [new file with mode: 0644]
ifupdown/networkinterfaces.py [new file with mode: 0644]
ifupdown/policymanager.py [new file with mode: 0644]
ifupdown/rtnetlink.py [new file with mode: 0644]
ifupdown/rtnetlink_api.py [new file with mode: 0644]
ifupdown/scheduler.py [new file with mode: 0644]
ifupdown/scheduler.py.orig [new file with mode: 0644]
ifupdown/statemanager.py [new file with mode: 0644]
ifupdown/template.py [new file with mode: 0644]
ifupdown/utils.py [new file with mode: 0644]
ifupdown2/KNOWN_ISSUES [deleted file]
ifupdown2/LICENSE [deleted file]
ifupdown2/README.rst [deleted file]
ifupdown2/TODO [deleted file]
ifupdown2/addons/address.py [deleted file]
ifupdown2/addons/addressvirtual.py [deleted file]
ifupdown2/addons/bridge.py [deleted file]
ifupdown2/addons/bridgevlan.py [deleted file]
ifupdown2/addons/dhcp.py [deleted file]
ifupdown2/addons/ethtool.py [deleted file]
ifupdown2/addons/ifenslave.py [deleted file]
ifupdown2/addons/loopback.py [deleted file]
ifupdown2/addons/mstpctl.py [deleted file]
ifupdown2/addons/usercmds.py [deleted file]
ifupdown2/addons/vlan.py [deleted file]
ifupdown2/addons/vrrpd.py [deleted file]
ifupdown2/addons/vxlan.py [deleted file]
ifupdown2/build.sh [deleted file]
ifupdown2/completion/ifup [deleted file]
ifupdown2/config/addons.conf [deleted file]
ifupdown2/config/ifupdown2.conf [deleted file]
ifupdown2/config/networking [deleted file]
ifupdown2/debian/copyright [deleted file]
ifupdown2/debian/python-ifupdown2.postinst [deleted file]
ifupdown2/debian/python-ifupdown2.postrm [deleted file]
ifupdown2/debian/python-ifupdown2.preinst [deleted file]
ifupdown2/docs/Makefile [deleted file]
ifupdown2/docs/examples/generate_interfaces.py [deleted file]
ifupdown2/docs/examples/interfaces [deleted file]
ifupdown2/docs/examples/interfaces_bridge_igmp_mstp [deleted file]
ifupdown2/docs/examples/interfaces_bridge_template_func [deleted file]
ifupdown2/docs/examples/interfaces_with_template [deleted file]
ifupdown2/docs/examples/vlan_aware_bridges/interfaces.basic [deleted file]
ifupdown2/docs/examples/vlan_aware_bridges/interfaces.vlan_prune_and_access_ports [deleted file]
ifupdown2/docs/examples/vlan_aware_bridges/interfaces.with_bonds [deleted file]
ifupdown2/docs/examples/vlan_aware_bridges/interfaces.with_clag [deleted file]
ifupdown2/docs/source/addonsapiref.rst [deleted file]
ifupdown2/docs/source/addonshelperapiref.rst [deleted file]
ifupdown2/docs/source/apiref.rst [deleted file]
ifupdown2/docs/source/conf.py [deleted file]
ifupdown2/docs/source/developmentcorner.rst [deleted file]
ifupdown2/docs/source/gettingstarted.rst [deleted file]
ifupdown2/docs/source/images/interfaces.png [deleted file]
ifupdown2/docs/source/images/interfaces_all.png [deleted file]
ifupdown2/docs/source/index.rst [deleted file]
ifupdown2/docs/source/intro.rst [deleted file]
ifupdown2/docs/source/userguide.rst [deleted file]
ifupdown2/ifupdown/__init__.py [deleted file]
ifupdown2/ifupdown/exceptions.py [deleted file]
ifupdown2/ifupdown/graph.py [deleted file]
ifupdown2/ifupdown/iface.py [deleted file]
ifupdown2/ifupdown/iff.py [deleted file]
ifupdown2/ifupdown/ifupdownbase.py [deleted file]
ifupdown2/ifupdown/ifupdownmain.py [deleted file]
ifupdown2/ifupdown/netlink.py [deleted file]
ifupdown2/ifupdown/networkinterfaces.py [deleted file]
ifupdown2/ifupdown/policymanager.py [deleted file]
ifupdown2/ifupdown/rtnetlink.py [deleted file]
ifupdown2/ifupdown/rtnetlink_api.py [deleted file]
ifupdown2/ifupdown/scheduler.py [deleted file]
ifupdown2/ifupdown/scheduler.py.orig [deleted file]
ifupdown2/ifupdown/statemanager.py [deleted file]
ifupdown2/ifupdown/template.py [deleted file]
ifupdown2/ifupdown/utils.py [deleted file]
ifupdown2/ifupdownaddons/__init__.py [deleted file]
ifupdown2/ifupdownaddons/bridgeutils.py [deleted file]
ifupdown2/ifupdownaddons/cache.py [deleted file]
ifupdown2/ifupdownaddons/dhclient.py [deleted file]
ifupdown2/ifupdownaddons/ifenslaveutil.py [deleted file]
ifupdown2/ifupdownaddons/iproute2.py [deleted file]
ifupdown2/ifupdownaddons/modulebase.py [deleted file]
ifupdown2/ifupdownaddons/mstpctlutil.py [deleted file]
ifupdown2/ifupdownaddons/utilsbase.py [deleted file]
ifupdown2/init.d/networking [deleted file]
ifupdown2/man.rst/ifquery.8.rst [deleted file]
ifupdown2/man.rst/ifreload.8.rst [deleted file]
ifupdown2/man.rst/ifup.8.rst [deleted file]
ifupdown2/man.rst/ifupdown-addons-interfaces.5.rst [deleted file]
ifupdown2/man.rst/interfaces.5.rst [deleted file]
ifupdown2/man/ifquery.8 [deleted file]
ifupdown2/man/ifreload.8 [deleted file]
ifupdown2/man/ifup.8 [deleted file]
ifupdown2/man/ifupdown-addons-interfaces.5 [deleted file]
ifupdown2/man/interfaces.5 [deleted file]
ifupdown2/sbin/ifupdown [deleted file]
ifupdown2/scripts/genmanpages.sh [deleted file]
ifupdown2/setup.py [deleted file]
ifupdown2/stdeb.cfg [deleted file]
ifupdown2/tests/ifstatetest [deleted file]
ifupdownaddons/__init__.py [new file with mode: 0644]
ifupdownaddons/bridgeutils.py [new file with mode: 0644]
ifupdownaddons/cache.py [new file with mode: 0644]
ifupdownaddons/dhclient.py [new file with mode: 0644]
ifupdownaddons/ifenslaveutil.py [new file with mode: 0644]
ifupdownaddons/iproute2.py [new file with mode: 0644]
ifupdownaddons/modulebase.py [new file with mode: 0644]
ifupdownaddons/mstpctlutil.py [new file with mode: 0644]
ifupdownaddons/utilsbase.py [new file with mode: 0644]
init.d/networking [new file with mode: 0644]
man.rst/ifquery.8.rst [new file with mode: 0644]
man.rst/ifreload.8.rst [new file with mode: 0644]
man.rst/ifup.8.rst [new file with mode: 0644]
man.rst/ifupdown-addons-interfaces.5.rst [new file with mode: 0644]
man.rst/interfaces.5.rst [new file with mode: 0644]
man/ifquery.8 [new file with mode: 0644]
man/ifreload.8 [new file with mode: 0644]
man/ifup.8 [new file with mode: 0644]
man/ifupdown-addons-interfaces.5 [new file with mode: 0644]
man/interfaces.5 [new file with mode: 0644]
sbin/ifupdown [new file with mode: 0755]
scripts/genmanpages.sh [new file with mode: 0755]
setup.py [new file with mode: 0755]
stdeb.cfg [new file with mode: 0644]
tests/ifstatetest [new file with mode: 0755]

diff --git a/KNOWN_ISSUES b/KNOWN_ISSUES
new file mode 100644 (file)
index 0000000..bcc3a4e
--- /dev/null
@@ -0,0 +1,6 @@
+- There is a state issue if multiple configuration blocks are present for the same interface in the interfaces file
+- `ifquery -r` can give wrong result if dhclient is running + static addresses are configured
+- `ifquery -r` status is success for success case and also for cases where there
+is no support for query yet
+- setup.py has ifupdown listed in data section instead of scripts: This is because default location for scripts is /usr/bin/. And ifupdown default location is /sbin. With newer versions we can specify --install-scripts directory. This needs to be fixed then.
+- and more :)
diff --git a/LICENSE b/LICENSE
new file mode 100644 (file)
index 0000000..22fbe5d
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,339 @@
+GNU GENERAL PUBLIC LICENSE
+                       Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc., <http://fsf.org/>
+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+                            Preamble
+
+  The licenses for most software are designed to take away your
+freedom to share and change it.  By contrast, the GNU General Public
+License is intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users.  This
+General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to
+using it.  (Some other Free Software Foundation software is covered by
+the GNU Lesser 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.
+
+    {description}
+    Copyright (C) {year}  {fullname}
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License along
+    with this program; if not, write to the Free Software Foundation, Inc.,
+    51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+
+Also add information on how to contact you by electronic and paper mail.
+
+If the program is interactive, make it output a short notice like this
+when it starts in an interactive mode:
+
+    Gnomovision version 69, Copyright (C) year name of author
+    Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+    This is free software, and you are welcome to redistribute it
+    under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License.  Of course, the commands you use may
+be called something other than `show w' and `show c'; they could even be
+mouse-clicks or menu items--whatever suits your program.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the program, if
+necessary.  Here is a sample; alter the names:
+
+  Yoyodyne, Inc., hereby disclaims all copyright interest in the program
+  `Gnomovision' (which makes passes at compilers) written by James Hacker.
+
+  {signature of Ty Coon}, 1 April 1989
+  Ty Coon, President of Vice
+
+This General Public License does not permit incorporating your program into
+proprietary programs.  If your program is a subroutine library, you may
+consider it more useful to permit linking proprietary applications with the
+library.  If this is what you want to do, use the GNU Lesser General
+Public License instead of this License.
\ No newline at end of file
diff --git a/README.rst b/README.rst
new file mode 100644 (file)
index 0000000..6187ec0
--- /dev/null
@@ -0,0 +1,74 @@
+python-ifupdown2
+================
+
+This package is a replacement for the debian ifupdown package.
+It is ifupdown re-written in python. It maintains the original ifupdown
+pluggable architecture and extends it further.
+
+The python-ifupdown2 package provides the infrastructure for
+parsing /etc/network/interfaces file, loading, scheduling and state
+management of interfaces.
+
+It dynamically loads python modules from /usr/share/ifupdownaddons.
+To remain compatible with other packages that depend on ifupdown,
+it also executes scripts under /etc/network/.
+To make the transition smoother, a python module under
+/usr/share/ifupdownaddons will override a script by the same name under
+/etc/network/.
+
+It publishes an interface object which is passed to all loadble python
+modules. For more details on adding a addon module, see the section on
+adding python modules.
+
+
+pluggable python modules:
+=========================
+Unlike original ifupdown, all interface configuration is moved to external
+python modules. That includes inet, inet6 and dhcp configurations.
+
+A set of default modules are included in the package.
+
+python-ifupdown2 expects a few things from the pluggable modules:
+- the module should implement a class by the same name
+- the interface object (class iface) and the operation to be performed is
+  passed to the modules
+- the python addon class should provide a few methods:
+       - run() : method to configure the interface.
+       - get_ops() : must return a list of operations it supports.
+               eg: 'pre-up', 'post-down'
+       - get_dependent_ifacenames() : must return a list of interfaces the
+         interface is dependent on. This is used to build the dependency list
+         for sorting and executing interfaces in dependency order.
+       - if the module supports -r option to ifquery, ie ability to construct the
+      ifaceobj from running state, it can optionally implement the
+      get_dependent_ifacenames_running() method, to return the list of
+      dependent interfaces derived from running state of the interface.
+      This is different from get_dependent_ifacenames() where the dependent
+      interfaces are derived from the interfaces config file (provided by the
+      user).
+
+Example: Address handling module /usr/share/ifupdownaddons/address.py
+
+
+build
+=====
+- get source
+
+- install build dependencies:
+    apt-get install python-stdeb
+    apt-get install python-docutils
+
+- cd <python-ifupdown2 sourcedir> && ./build.sh
+
+  (generates python-ifupdown2-<ver>.deb)
+
+install
+=======
+
+- remove existing ifupdown package
+  dpkg -r ifupdown
+
+- install python-ifupdown2 using `dpkg -i`
+
+- or install from deb
+    dpkg -i python-ifupdown2-<ver>.deb
diff --git a/TODO b/TODO
new file mode 100644 (file)
index 0000000..aff9cd5
--- /dev/null
+++ b/TODO
@@ -0,0 +1,36 @@
+TODO:
+====
+- support old ifupdown state file /run/network/ifstate. Because some app's seem to use it
+- support for debian ifupdown methods: tunnel, v4tunnel, 6to4, ppp, wvdial, ipv4ll
+- support for debian ifupdown ipv6 auto method
+- support for debian ifupdown CAN address family
+- Compat : support for LOGICAL interfaces
+- dry-run improvement: It skips the cache completely. Which means It tells you the commands it would execute if the system is clean. Its not smart enought to say what it will really execute given the state of the system
+
+- Ifquery does not report link status, mainly because it reports only in terms of /etc/network/interfaces attributes. Plan to fix that
+- more Documentation
+- Priorities for addon modules
+- have ability to also run uninstall on interfaces that dont have any config
+- ifup hotplug support (basically needs some testing and fixing broken things)
+- -q quiet option
+- support for /etc/networking.defaults
+- implement legacy ifupdown mapping feature
+- support for the following ifupdown options:
+    -o OPTION=VALUE     set OPTION to VALUE as though it were in
+                        /etc/network/interfaces
+    --no-mappings       don't run any mappings
+    --no-scripts        don't run any hook scripts
+- parallel implementation
+- Test all original ifupdown options for compatibility
+- Test with ifupdown-extra, ifmetric, ifupdown-scripts-zg2
+- export other environment variables to bash scripts (for backward compatibility):
+       IFACE  physical name of the interface being processed
+        LOGICAL logical name of the interface being processed
+        ADDRFAM address family of the interface
+        METHOD method of the interface (e.g., static)
+        MODE   start if run from ifup, stop if run from ifdown
+        PHASE  as per MODE, but with finer granularity, distinguishing the pre-
+               up, post-up, pre-down and post-down phases.
+        VERBOSITY indicates  whether --verbose was used; set to 1 if so, 0 if not.
+        PATH   the  command   search   path:   /usr/local/sbin:/usr/local/bin:‐
+               /usr/sbin:/usr/bin:/sbin:/bin
diff --git a/addons/address.py b/addons/address.py
new file mode 100644 (file)
index 0000000..8d9bb75
--- /dev/null
@@ -0,0 +1,394 @@
+#!/usr/bin/python
+#
+# Copyright 2014 Cumulus Networks, Inc. All rights reserved.
+# Author: Roopa Prabhu, roopa@cumulusnetworks.com
+#
+
+try:
+    from ipaddr import IPNetwork
+    from sets import Set
+    from ifupdown.iface import *
+    from ifupdownaddons.modulebase import moduleBase
+    from ifupdownaddons.iproute2 import iproute2
+    from ifupdownaddons.dhclient import dhclient
+except ImportError, e:
+    raise ImportError (str(e) + "- required module not found")
+
+class address(moduleBase):
+    """  ifupdown2 addon module to configure address, mtu, hwaddress, alias
+    (description) on an interface """
+
+    _modinfo = {'mhelp' : 'address configuration module for interfaces',
+                'attrs': {
+                      'address' :
+                            {'help' : 'ipv4 or ipv6 addresses',
+                             'example' : ['address 10.0.12.3/24',
+                             'address 2000:1000:1000:1000:3::5/128']},
+                      'netmask' :
+                            {'help': 'netmask',
+                             'example' : ['netmask 255.255.255.0'],
+                             'compat' : True},
+                      'broadcast' :
+                            {'help': 'broadcast address',
+                             'example' : ['broadcast 10.0.1.255']},
+                      'scope' :
+                            {'help': 'scope',
+                             'example' : ['scope host']},
+                      'preferred-lifetime' :
+                            {'help': 'preferred lifetime',
+                             'example' : ['preferred-lifetime forever',
+                                          'preferred-lifetime 10']},
+                      'gateway' :
+                            {'help': 'default gateway',
+                             'example' : ['gateway 255.255.255.0']},
+                      'mtu' :
+                            { 'help': 'interface mtu',
+                              'example' : ['mtu 1600'],
+                              'default' : '1500'},
+                      'hwaddress' :
+                            {'help' : 'hw address',
+                             'example': ['hwaddress 44:38:39:00:27:b8']},
+                      'alias' :
+                            { 'help': 'description/alias',
+                              'example' : ['alias testnetwork']},
+                      'address-purge' :
+                            { 'help': 'purge existing addresses. By default ' +
+                              'any existing ip addresses on an interface are ' +
+                              'purged to match persistant addresses in the ' +
+                              'interfaces file. Set this attribute to \'no\'' +
+                              'if you want to preserve existing addresses',
+                              'default' : 'yes',
+                              'example' : ['address-purge yes/no']}}}
+
+    def __init__(self, *args, **kargs):
+        moduleBase.__init__(self, *args, **kargs)
+        self.ipcmd = None
+        self._bridge_fdb_query_cache = {}
+
+    def _address_valid(self, addrs):
+        if not addrs:
+           return False
+        if any(map(lambda a: True if a[:7] != '0.0.0.0'
+                else False, addrs)):
+           return True
+        return False
+
+    def _process_bridge(self, ifaceobj, up):
+        hwaddress = ifaceobj.get_attr_value_first('hwaddress')
+        addrs = ifaceobj.get_attr_value_first('address')
+        is_vlan_dev_on_vlan_aware_bridge = False
+        is_bridge = self.ipcmd.is_bridge(ifaceobj.name)
+        if not is_bridge:
+            if '.' in ifaceobj.name:
+                (bridgename, vlan) = ifaceobj.name.split('.')
+                is_vlan_dev_on_vlan_aware_bridge = self.ipcmd.bridge_is_vlan_aware(bridgename)
+        if ((is_bridge and not self.ipcmd.bridge_is_vlan_aware(ifaceobj.name))
+                        or is_vlan_dev_on_vlan_aware_bridge):
+           if self._address_valid(addrs):
+              if up:
+                self.write_file('/proc/sys/net/ipv4/conf/%s' %ifaceobj.name +
+                                '/arp_accept', '1')
+              else:
+                self.write_file('/proc/sys/net/ipv4/conf/%s' %ifaceobj.name +
+                                '/arp_accept', '0')
+        if hwaddress and is_vlan_dev_on_vlan_aware_bridge:
+           if up:
+              self.ipcmd.bridge_fdb_add(bridgename, hwaddress, vlan)
+           else:
+              self.ipcmd.bridge_fdb_del(bridgename, hwaddress, vlan)
+
+    def _inet_address_config(self, ifaceobj):
+        purge_addresses = ifaceobj.get_attr_value_first('address-purge')
+        if not purge_addresses:
+           purge_addresses = 'yes'
+        newaddrs = []
+        addrs = ifaceobj.get_attr_value('address')
+        if addrs:
+            if ifaceobj.role & ifaceRole.SLAVE:
+                # we must not configure an IP address if the interface is enslaved
+                self.log_warn('interface %s is enslaved and cannot have an IP Address' % \
+                              (ifaceobj.name))
+                return
+            # If user address is not in CIDR notation, convert them to CIDR
+            for addr_index in range(0, len(addrs)):
+                addr = addrs[addr_index]
+                if '/' in addr:
+                    newaddrs.append(addr)
+                    continue
+                netmask = ifaceobj.get_attr_value_n('netmask', addr_index)
+                if netmask:
+                    prefixlen = IPNetwork('%s' %addr +
+                                '/%s' %netmask).prefixlen
+                    newaddrs.append(addr + '/%s' %prefixlen)
+                else:
+                    newaddrs.append(addr)
+
+        if (not self.PERFMODE and
+                not (ifaceobj.flags & iface.HAS_SIBLINGS) and
+                purge_addresses == 'yes'):
+            # if perfmode is not set and also if iface has no sibling
+            # objects, purge addresses that are not present in the new
+            # config
+            runningaddrs = self.ipcmd.addr_get(ifaceobj.name, details=False)
+            if newaddrs == runningaddrs:
+                return
+            try:
+                # if primary address is not same, there is no need to keep any.
+                # reset all addresses
+                if (newaddrs and runningaddrs and
+                        (newaddrs[0] != runningaddrs[0])):
+                    self.ipcmd.del_addr_all(ifaceobj.name)
+                else:
+                    self.ipcmd.del_addr_all(ifaceobj.name, newaddrs)
+            except Exception, e:
+                self.log_warn(str(e))
+        if not newaddrs:
+            return
+        for addr_index in range(0, len(newaddrs)):
+            try:
+                self.ipcmd.addr_add(ifaceobj.name, newaddrs[addr_index],
+                    ifaceobj.get_attr_value_n('broadcast', addr_index),
+                    ifaceobj.get_attr_value_n('pointopoint',addr_index),
+                    ifaceobj.get_attr_value_n('scope', addr_index),
+                    ifaceobj.get_attr_value_n('preferred-lifetime', addr_index))
+            except Exception, e:
+                self.log_error(str(e))
+
+    def _up(self, ifaceobj):
+        if not self.ipcmd.link_exists(ifaceobj.name):
+            return
+        addr_method = ifaceobj.addr_method
+        try:
+            # release any stale dhcp addresses if present
+            if (addr_method != "dhcp" and not self.PERFMODE and
+                    not (ifaceobj.flags & iface.HAS_SIBLINGS)):
+                # if not running in perf mode and ifaceobj does not have
+                # any sibling iface objects, kill any stale dhclient
+                # processes
+                dhclientcmd = dhclient()
+                if dhclient.is_running(ifaceobj.name):
+                    # release any dhcp leases
+                    dhclientcmd.release(ifaceobj.name)
+                elif dhclient.is_running6(ifaceobj.name):
+                    dhclientcmd.release6(ifaceobj.name)
+        except:
+            pass
+
+        self.ipcmd.batch_start()
+        if addr_method != "dhcp":
+            self._inet_address_config(ifaceobj)
+        mtu = ifaceobj.get_attr_value_first('mtu')
+        if mtu:
+           self.ipcmd.link_set(ifaceobj.name, 'mtu', mtu)
+        alias = ifaceobj.get_attr_value_first('alias')
+        if alias:
+           self.ipcmd.link_set_alias(ifaceobj.name, alias)
+        hwaddress = ifaceobj.get_attr_value_first('hwaddress')
+        if hwaddress:
+            self.ipcmd.link_set(ifaceobj.name, 'address', hwaddress)
+        self.ipcmd.batch_commit()
+
+        try:
+            # Handle special things on a bridge
+            self._process_bridge(ifaceobj, True)
+        except Exception, e:
+            self.log_warn('%s: %s' %(ifaceobj.name, str(e)))
+            pass
+
+        if addr_method != "dhcp":
+            self.ipcmd.route_add_gateway(ifaceobj.name,
+                    ifaceobj.get_attr_value_first('gateway'))
+
+    def _down(self, ifaceobj):
+        try:
+            if not self.ipcmd.link_exists(ifaceobj.name):
+                return
+            addr_method = ifaceobj.addr_method
+            if addr_method != "dhcp":
+                self.ipcmd.route_del_gateway(ifaceobj.name,
+                    ifaceobj.get_attr_value_first('gateway'),
+                    ifaceobj.get_attr_value_first('metric'))
+                self.ipcmd.del_addr_all(ifaceobj.name)
+            alias = ifaceobj.get_attr_value_first('alias')
+            if alias:
+                self.ipcmd.link_set(ifaceobj.name, 'alias', "\'\'")
+            # XXX hwaddress reset cannot happen because we dont know last
+            # address.
+
+            # Handle special things on a bridge
+            self._process_bridge(ifaceobj, False)
+        except Exception, e:
+            self.logger.debug('%s : %s' %(ifaceobj.name, str(e)))
+            pass
+
+    def _get_iface_addresses(self, ifaceobj):
+        addrlist = ifaceobj.get_attr_value('address')
+        outaddrlist = []
+
+        if not addrlist: return None
+        for addrindex in range(0, len(addrlist)):
+            addr = addrlist[addrindex]
+            netmask = ifaceobj.get_attr_value_n('netmask', addrindex)
+            if netmask:
+                prefixlen = IPNetwork('%s' %addr +
+                                '/%s' %netmask).prefixlen
+                addr = addr + '/%s' %prefixlen
+            outaddrlist.append(addr)
+        return outaddrlist
+
+    def _get_bridge_fdbs(self, bridgename, vlan):
+        fdbs = self._bridge_fdb_query_cache.get(bridgename)
+        if not fdbs:
+           fdbs = self.ipcmd.bridge_fdb_show_dev(bridgename)
+           if not fdbs:
+              return
+           self._bridge_fdb_query_cache[bridgename] = fdbs
+        return fdbs.get(vlan)
+
+    def _check_addresses_in_bridge(self, ifaceobj, hwaddress):
+        """ If the device is a bridge, make sure the addresses
+        are in the bridge """
+        if '.' in ifaceobj.name:
+            (bridgename, vlan) = ifaceobj.name.split('.')
+            if self.ipcmd.bridge_is_vlan_aware(bridgename):
+                fdb_addrs = self._get_bridge_fdbs(bridgename, vlan)
+                if not fdb_addrs or hwaddress not in fdb_addrs:
+                   return False
+        return True
+
+    def _query_check(self, ifaceobj, ifaceobjcurr):
+        runningaddrsdict = None
+        if not self.ipcmd.link_exists(ifaceobj.name):
+            self.logger.debug('iface %s not found' %ifaceobj.name)
+            return
+        addr_method = ifaceobj.addr_method
+        self.query_n_update_ifaceobjcurr_attr(ifaceobj, ifaceobjcurr,
+                'mtu', self.ipcmd.link_get_mtu)
+        hwaddress = ifaceobj.get_attr_value_first('hwaddress')
+        if hwaddress:
+            rhwaddress = self.ipcmd.link_get_hwaddress(ifaceobj.name)
+            if not rhwaddress  or rhwaddress != hwaddress:
+               ifaceobjcurr.update_config_with_status('hwaddress', rhwaddress,
+                       1)
+            elif not self._check_addresses_in_bridge(ifaceobj, hwaddress):
+               # XXX: hw address is not in bridge
+               ifaceobjcurr.update_config_with_status('hwaddress', rhwaddress,
+                       1)
+               ifaceobjcurr.status_str = 'bridge fdb error'
+            else:
+               ifaceobjcurr.update_config_with_status('hwaddress', rhwaddress,
+                       0)
+        self.query_n_update_ifaceobjcurr_attr(ifaceobj, ifaceobjcurr,
+                    'alias', self.ipcmd.link_get_alias)
+        # compare addresses
+        if addr_method == 'dhcp':
+           return
+        addrs = self._get_iface_addresses(ifaceobj)
+        runningaddrsdict = self.ipcmd.addr_get(ifaceobj.name)
+
+        # Set ifaceobjcurr method and family
+        ifaceobjcurr.addr_method = ifaceobj.addr_method
+        ifaceobjcurr.addr_family = ifaceobj.addr_family
+        if not runningaddrsdict and not addrs:
+            return
+        runningaddrs = runningaddrsdict.keys() if runningaddrsdict else []
+        if runningaddrs != addrs:
+            runningaddrsset = set(runningaddrs) if runningaddrs else set([])
+            addrsset = set(addrs) if addrs else set([])
+            if (ifaceobj.flags & iface.HAS_SIBLINGS):
+                if not addrsset:
+                    return
+                # only check for addresses present in running config
+                addrsdiff = addrsset.difference(runningaddrsset)
+                for addr in addrs:
+                    if addr in addrsdiff:
+                        ifaceobjcurr.update_config_with_status('address',
+                                    addr, 1)
+                    else:
+                        ifaceobjcurr.update_config_with_status('address',
+                                    addr, 0)
+            else:
+                addrsdiff = addrsset.symmetric_difference(runningaddrsset)
+                for addr in addrsset.union(runningaddrsset):
+                    if addr in addrsdiff:
+                        ifaceobjcurr.update_config_with_status('address',
+                                                               addr, 1)
+                    else:
+                        ifaceobjcurr.update_config_with_status('address',
+                                                               addr, 0)
+        elif addrs:
+            [ifaceobjcurr.update_config_with_status('address',
+                       addr, 0) for addr in addrs]
+        #XXXX Check broadcast address, scope, etc
+        return
+
+    def _query_running(self, ifaceobjrunning):
+        if not self.ipcmd.link_exists(ifaceobjrunning.name):
+            self.logger.debug('iface %s not found' %ifaceobjrunning.name)
+            return
+        dhclientcmd = dhclient()
+        if (dhclientcmd.is_running(ifaceobjrunning.name) or
+                dhclientcmd.is_running6(ifaceobjrunning.name)):
+            # If dhcp is configured on the interface, we skip it
+            return 
+        isloopback = self.ipcmd.link_isloopback(ifaceobjrunning.name)
+        if isloopback:
+            default_addrs = ['127.0.0.1/8', '::1/128']
+            ifaceobjrunning.addr_family = 'inet'
+            ifaceobjrunning.addr_method = 'loopback'
+        else:
+            default_addrs = []
+        runningaddrsdict = self.ipcmd.addr_get(ifaceobjrunning.name)
+        if runningaddrsdict:
+            [ifaceobjrunning.update_config('address', addr)
+                for addr, addrattrs in runningaddrsdict.items()
+                if addr not in default_addrs]
+        mtu = self.ipcmd.link_get_mtu(ifaceobjrunning.name)
+        if (mtu and
+                (ifaceobjrunning.name == 'lo' and mtu != '16436') or
+                (ifaceobjrunning.name != 'lo' and
+                    mtu != self.get_mod_subattr('mtu', 'default'))):
+                ifaceobjrunning.update_config('mtu', mtu)
+        alias = self.ipcmd.link_get_alias(ifaceobjrunning.name)
+        if alias: 
+            ifaceobjrunning.update_config('alias', alias)
+
+    _run_ops = {'up' : _up,
+               'down' : _down,
+               'query-checkcurr' : _query_check,
+               'query-running' : _query_running }
+
+    def get_ops(self):
+        """ returns list of ops supported by this module """
+        return self._run_ops.keys()
+
+    def _init_command_handlers(self):
+        if not self.ipcmd:
+            self.ipcmd = iproute2(**self.get_flags())
+
+    def run(self, ifaceobj, operation, query_ifaceobj=None, **extra_args):
+        """ run address configuration on the interface object passed as argument
+
+        Args:
+            **ifaceobj** (object): iface object
+
+            **operation** (str): any of 'up', 'down', 'query-checkcurr',
+                                 'query-running'
+        Kwargs:
+            query_ifaceobj (object): query check ifaceobject. This is only
+                valid when op is 'query-checkcurr'. It is an object same as
+                ifaceobj, but contains running attribute values and its config
+                status. The modules can use it to return queried running state
+                of interfaces. status is success if the running state is same
+                as user required state in ifaceobj. error otherwise.
+        """
+        if ifaceobj.type == ifaceType.BRIDGE_VLAN:
+           return
+        op_handler = self._run_ops.get(operation)
+        if not op_handler:
+            return
+        self._init_command_handlers()
+        if operation == 'query-checkcurr':
+            op_handler(self, ifaceobj, query_ifaceobj)
+        else:
+            op_handler(self, ifaceobj)
diff --git a/addons/addressvirtual.py b/addons/addressvirtual.py
new file mode 100644 (file)
index 0000000..98ac536
--- /dev/null
@@ -0,0 +1,321 @@
+#!/usr/bin/python
+#
+# Copyright 2014 Cumulus Networks, Inc. All rights reserved.
+# Author: Roopa Prabhu, roopa@cumulusnetworks.com
+#
+
+from ifupdown.iface import *
+from ifupdownaddons.modulebase import moduleBase
+from ifupdownaddons.iproute2 import iproute2
+import ifupdown.rtnetlink_api as rtnetlink_api
+from ipaddr import IPNetwork
+import logging
+import os
+import glob
+
+class addressvirtual(moduleBase):
+    """  ifupdown2 addon module to configure virtual addresses """
+
+    _modinfo = {'mhelp' : 'address module configures virtual addresses for ' +
+                          'interfaces. It creates a macvlan interface for ' +
+                          'every mac ip address-virtual line',
+                'attrs' : {
+                    'address-virtual' :
+                        { 'help' : 'bridge router virtual mac and ip',
+                          'example' : ['address-virtual 00:11:22:33:44:01 11.0.1.254/24 11.0.1.254/24']}
+                 }}
+
+
+    def __init__(self, *args, **kargs):
+        moduleBase.__init__(self, *args, **kargs)
+        self.ipcmd = None
+        self._bridge_fdb_query_cache = {}
+
+    def _is_supported(self, ifaceobj):
+        if ifaceobj.get_attr_value_first('address-virtual'):
+            return True
+        return False
+
+    def _get_macvlan_prefix(self, ifaceobj):
+        return '%s-v' %ifaceobj.name[0:13].replace('.', '-')
+
+    def _add_addresses_to_bridge(self, ifaceobj, hwaddress):
+        # XXX: batch the addresses
+        if '.' in ifaceobj.name:
+            (bridgename, vlan) = ifaceobj.name.split('.')
+            if self.ipcmd.bridge_is_vlan_aware(bridgename):
+                [self.ipcmd.bridge_fdb_add(bridgename, addr,
+                    vlan) for addr in hwaddress]
+        elif self.ipcmd.is_bridge(ifaceobj.name):
+            [self.ipcmd.bridge_fdb_add(ifaceobj.name, addr)
+                    for addr in hwaddress]
+
+    def _remove_addresses_from_bridge(self, ifaceobj, hwaddress):
+        # XXX: batch the addresses
+        bridgename = None
+        if '.' in ifaceobj.name:
+            if self.ipcmd.bridge_is_vlan_aware(bridgename):
+                (bridgename, vlan) = ifaceobj.name.split('.')
+        elif self.ipcmd.is_bridge(ifaceobj.name):
+            vlan = None
+            bridgename = ifaceobj.name
+        if not bridgename:
+            return
+        for addr in hwaddress:
+            try:
+                self.ipcmd.bridge_fdb_del(bridgename, addr, vlan)
+            except Exception, e:
+                self.logger.debug("%s: %s" %(ifaceobj.name, str(e)))
+                pass
+
+    def _get_bridge_fdbs(self, bridgename, vlan):
+        fdbs = self._bridge_fdb_query_cache.get(bridgename)
+        if not fdbs:
+           fdbs = self.ipcmd.bridge_fdb_show_dev(bridgename)
+           if not fdbs:
+              return
+           self._bridge_fdb_query_cache[bridgename] = fdbs
+        return fdbs.get(vlan)
+
+    def _check_addresses_in_bridge(self, ifaceobj, hwaddress):
+        """ If the device is a bridge, make sure the addresses
+        are in the bridge """
+        if '.' in ifaceobj.name:
+            (bridgename, vlan) = ifaceobj.name.split('.')
+            if self.ipcmd.bridge_is_vlan_aware(bridgename):
+                fdb_addrs = self._get_bridge_fdbs(bridgename, vlan)
+                if not fdb_addrs or hwaddress not in fdb_addrs:
+                   return False
+        return True
+
+    def _fix_connected_route(self, ifaceobj, vifacename, addr):
+        #
+        # XXX: Hack to make sure the primary address 
+        # is the first in the routing table.
+        #
+        # We use `ip route get` on the vrr network to see which
+        # device the kernel returns. if it is the mac vlan device,
+        # flap the macvlan device to adjust the routing table entry.
+        # 
+        # flapping the macvlan device makes sure the macvlan
+        # connected route goes through delete + add, hence adjusting
+        # the order in the routing table.
+        #
+        try:
+            self.logger.info('%s: checking route entry ...' %ifaceobj.name)
+            ip = IPNetwork(addr)
+            route_prefix = '%s/%d' %(ip.network, ip.prefixlen)
+
+            dev = self.ipcmd.ip_route_get_dev(route_prefix)
+            if dev and dev == vifacename:
+                self.logger.info('%s: preferred routing entry ' %ifaceobj.name +
+                                 'seems to be of the macvlan dev %s'
+                                 %vifacename +
+                                 ' .. flapping macvlan dev to fix entry.')
+                self.ipcmd.link_down(vifacename)
+                self.ipcmd.link_up(vifacename)
+        except Exception, e:
+            self.logger.debug('%s: fixing route entry failed (%s)'
+                              %str(e))
+            pass
+
+    def _apply_address_config(self, ifaceobj, address_virtual_list):
+        purge_existing = False if self.PERFMODE else True
+
+        hwaddress = []
+        self.ipcmd.batch_start()
+        av_idx = 0
+        macvlan_prefix = self._get_macvlan_prefix(ifaceobj)
+        for av in address_virtual_list:
+            av_attrs = av.split()
+            if len(av_attrs) < 2:
+                self.logger.warn("%s: incorrect address-virtual attrs '%s'"
+                             %(ifaceobj.name,  av))
+                av_idx += 1
+                continue
+
+            # Create a macvlan device on this device and set the virtual
+            # router mac and ip on it
+            link_created = False
+            macvlan_ifacename = '%s%d' %(macvlan_prefix, av_idx)
+            if not self.ipcmd.link_exists(macvlan_ifacename):
+                rtnetlink_api.rtnl_api.create_macvlan(macvlan_ifacename,
+                                                      ifaceobj.name)
+                link_created = True
+            if av_attrs[0] != 'None':
+                self.ipcmd.link_set_hwaddress(macvlan_ifacename, av_attrs[0])
+                hwaddress.append(av_attrs[0])
+            self.ipcmd.addr_add_multiple(macvlan_ifacename, av_attrs[1:],
+                                         purge_existing)
+            # If link existed before, flap the link
+            if not link_created:
+                self._fix_connected_route(ifaceobj, macvlan_ifacename,
+                                          av_attrs[1])
+            av_idx += 1
+        self.ipcmd.batch_commit()
+
+        # if ifaceobj is a bridge and bridge is a vlan aware bridge
+        # add the vid to the bridge
+        self._add_addresses_to_bridge(ifaceobj, hwaddress)
+
+    def _remove_running_address_config(self, ifaceobj):
+        if not self.ipcmd.link_exists(ifaceobj.name):
+            return
+        hwaddress = []
+        self.ipcmd.batch_start()
+        macvlan_prefix = self._get_macvlan_prefix(ifaceobj)
+        for macvlan_ifacename in glob.glob("/sys/class/net/%s-*" %macvlan_prefix):
+            macvlan_ifacename = os.path.basename(macvlan_ifacename)
+            if not self.ipcmd.link_exists(macvlan_ifacename):
+                continue
+            hwaddress.append(self.ipcmd.link_get_hwaddress(macvlan_ifacename))
+            self.ipcmd.link_delete(os.path.basename(macvlan_ifacename))
+            # XXX: Also delete any fdb addresses. This requires, checking mac address
+            # on individual macvlan interfaces and deleting the vlan from that.
+        self.ipcmd.batch_commit()
+        if any(hwaddress):
+            self._remove_addresses_from_bridge(ifaceobj, hwaddress)
+
+    def _remove_address_config(self, ifaceobj, address_virtual_list=None):
+        if not address_virtual_list:
+            self._remove_running_address_config(ifaceobj)
+            return
+
+        if not self.ipcmd.link_exists(ifaceobj.name):
+            return
+        hwaddress = []
+        self.ipcmd.batch_start()
+        av_idx = 0
+        macvlan_prefix = self._get_macvlan_prefix(ifaceobj)
+        for av in address_virtual_list:
+            av_attrs = av.split()
+            if len(av_attrs) < 2:
+                self.logger.warn("%s: incorrect address-virtual attrs '%s'"
+                             %(ifaceobj.name,  av))
+                av_idx += 1
+                continue
+
+            # Delete the macvlan device on this device
+            macvlan_ifacename = '%s%d' %(macvlan_prefix, av_idx)
+            self.ipcmd.link_delete(os.path.basename(macvlan_ifacename))
+            if av_attrs[0] != 'None':
+                hwaddress.append(av_attrs[0])
+            av_idx += 1
+        self.ipcmd.batch_commit()
+        self._remove_addresses_from_bridge(ifaceobj, hwaddress)
+
+    def _up(self, ifaceobj):
+        address_virtual_list = ifaceobj.get_attr_value('address-virtual')
+        if not address_virtual_list:
+            # XXX: address virtual is not present. In which case,
+            # delete stale macvlan devices.
+            self._remove_address_config(ifaceobj, address_virtual_list)
+            return
+
+        if not self.ipcmd.link_exists(ifaceobj.name):
+            return
+        self._apply_address_config(ifaceobj, address_virtual_list)
+
+    def _down(self, ifaceobj):
+        try:
+            self._remove_address_config(ifaceobj,
+                         ifaceobj.get_attr_value('address-virtual'))
+        except Exception, e:
+            self.log_warn(str(e))
+
+    def _query_check(self, ifaceobj, ifaceobjcurr):
+        address_virtual_list = ifaceobj.get_attr_value('address-virtual')
+        if not address_virtual_list:
+            return
+        if not self.ipcmd.link_exists(ifaceobj.name):
+            return
+        av_idx = 0
+        macvlan_prefix = self._get_macvlan_prefix(ifaceobj)
+        for address_virtual in address_virtual_list:
+            av_attrs = address_virtual.split()
+            if len(av_attrs) < 2:
+                self.logger.warn("%s: incorrect address-virtual attrs '%s'"
+                             %(ifaceobj.name,  address_virtual))
+                av_idx += 1
+                continue
+
+            # Check if the macvlan device on this interface
+            macvlan_ifacename = '%s%d' %(macvlan_prefix, av_idx)
+            if not self.ipcmd.link_exists(macvlan_ifacename):
+                ifaceobjcurr.update_config_with_status('address-virtual',
+                            '', 1)
+                av_idx += 1
+                continue
+            # Check mac and ip address
+            rhwaddress = self.ipcmd.link_get_hwaddress(macvlan_ifacename)
+            raddrs = self.ipcmd.addr_get(macvlan_ifacename)
+            if not raddrs or not rhwaddress:
+               ifaceobjcurr.update_config_with_status('address-virtual', '', 1)
+               av_idx += 1
+               continue
+            raddrs = raddrs.keys()
+            if (rhwaddress == av_attrs[0] and raddrs == av_attrs[1:] and
+                    self._check_addresses_in_bridge(ifaceobj, av_attrs[0])):
+               ifaceobjcurr.update_config_with_status('address-virtual',
+                            address_virtual, 0)
+            else:
+               raddress_virtual = '%s %s' %(rhwaddress, ' '.join(raddrs))
+               ifaceobjcurr.update_config_with_status('address-virtual',
+                            raddress_virtual, 1)
+            av_idx += 1
+        return
+
+    def _query_running(self, ifaceobjrunning):
+        macvlan_prefix = self._get_macvlan_prefix(ifaceobjrunning)
+        address_virtuals = glob.glob("/sys/class/net/%s*" %macvlan_prefix)
+        for av in address_virtuals:
+            macvlan_ifacename = os.path.basename(av)
+            rhwaddress = self.ipcmd.link_get_hwaddress(macvlan_ifacename)
+            raddress = self.ipcmd.addr_get(macvlan_ifacename)
+            if not raddress:
+                self.logger.warn('%s: no running addresses'
+                                 %ifaceobjrunning.name)
+                raddress = []
+            ifaceobjrunning.update_config('address-virtual',
+                            '%s %s' %(rhwaddress, ''.join(raddress)))
+        return
+
+    _run_ops = {'up' : _up,
+               'down' : _down,
+               'query-checkcurr' : _query_check,
+               'query-running' : _query_running}
+
+    def get_ops(self):
+        """ returns list of ops supported by this module """
+        return self._run_ops.keys()
+
+    def _init_command_handlers(self):
+        if not self.ipcmd:
+            self.ipcmd = iproute2(**self.get_flags())
+
+    def run(self, ifaceobj, operation, query_ifaceobj=None, **extra_args):
+        """ run vlan configuration on the interface object passed as argument
+
+        Args:
+            **ifaceobj** (object): iface object
+
+            **operation** (str): any of 'pre-up', 'post-down', 'query-checkcurr',
+                                 'query-running'
+        Kwargs:
+            **query_ifaceobj** (object): query check ifaceobject. This is only
+                valid when op is 'query-checkcurr'. It is an object same as
+                ifaceobj, but contains running attribute values and its config
+                status. The modules can use it to return queried running state
+                of interfaces. status is success if the running state is same
+                as user required state in ifaceobj. error otherwise.
+        """
+        if ifaceobj.type == ifaceType.BRIDGE_VLAN:
+            return
+        op_handler = self._run_ops.get(operation)
+        if not op_handler:
+            return
+        self._init_command_handlers()
+        if operation == 'query-checkcurr':
+            op_handler(self, ifaceobj, query_ifaceobj)
+        else:
+            op_handler(self, ifaceobj)
diff --git a/addons/bridge.py b/addons/bridge.py
new file mode 100644 (file)
index 0000000..012465a
--- /dev/null
@@ -0,0 +1,1575 @@
+#!/usr/bin/python
+#
+# Copyright 2014 Cumulus Networks, Inc. All rights reserved.
+# Author: Roopa Prabhu, roopa@cumulusnetworks.com
+#
+
+from sets import Set
+from ifupdown.iface import *
+from ifupdownaddons.modulebase import moduleBase
+from ifupdownaddons.bridgeutils import brctl
+from ifupdownaddons.iproute2 import iproute2
+from collections import Counter
+import ifupdown.rtnetlink_api as rtnetlink_api
+import itertools
+import re
+import time
+
+class bridgeFlags:
+    PORT_PROCESSED = 0x1
+
+class bridge(moduleBase):
+    """  ifupdown2 addon module to configure linux bridges """
+
+    _modinfo = { 'mhelp' : 'Bridge configuration module. Supports both ' +
+                    'vlan aware and non vlan aware bridges. For the vlan ' +
+                    'aware bridge, the port specific attributes must be ' +
+                    'specified under the port. And for vlan unaware bridge ' +
+                    'port specific attributes must be specified under the ' +
+                    'bridge.',
+                 'attrs' : {
+                   'bridge-vlan-aware' :
+                        {'help' : 'vlan aware bridge. Setting this ' +
+                                  'attribute to yes enables vlan filtering' +
+                                  ' on the bridge',
+                         'example' : ['bridge-vlan-aware yes/no']},
+                   'bridge-ports' :
+                        {'help' : 'bridge ports',
+                         'required' : True,
+                         'example' : ['bridge-ports swp1.100 swp2.100 swp3.100',
+                                      'bridge-ports glob swp1-3.100',
+                                      'bridge-ports regex (swp[1|2|3].100)']},
+                   'bridge-stp' :
+                        {'help': 'bridge-stp yes/no',
+                         'example' : ['bridge-stp no'],
+                         'validvals' : ['yes', 'on', 'off', 'no'],
+                         'default' : 'no'},
+                   'bridge-bridgeprio' :
+                        {'help': 'bridge priority',
+                         'example' : ['bridge-bridgeprio 32768'],
+                         'default' : '32768'},
+                   'bridge-ageing' :
+                       {'help': 'bridge ageing',
+                         'example' : ['bridge-ageing 300'],
+                         'default' : '300'},
+                   'bridge-fd' :
+                        { 'help' : 'bridge forward delay',
+                          'example' : ['bridge-fd 15'],
+                          'default' : '15'},
+                   'bridge-gcint' :
+                        # XXX: recheck values
+                        { 'help' : 'bridge garbage collection interval in secs',
+                          'example' : ['bridge-gcint 4'],
+                          'default' : '4'},
+                   'bridge-hello' :
+                        { 'help' : 'bridge set hello time',
+                          'example' : ['bridge-hello 2'],
+                          'default' : '2'},
+                   'bridge-maxage' :
+                        { 'help' : 'bridge set maxage',
+                          'example' : ['bridge-maxage 20'],
+                          'default' : '20'},
+                   'bridge-pathcosts' :
+                        { 'help' : 'bridge set port path costs',
+                          'example' : ['bridge-pathcosts swp1=100 swp2=100'],
+                          'default' : '100'},
+                   'bridge-portprios' :
+                        { 'help' : 'bridge port prios',
+                          'example' : ['bridge-portprios swp1=32 swp2=32'],
+                          'default' : '32'},
+                   'bridge-mclmc' :
+                        { 'help' : 'set multicast last member count',
+                          'example' : ['bridge-mclmc 2'],
+                          'default' : '2'},
+                    'bridge-mcrouter' :
+                        { 'help' : 'set multicast router',
+                          'default' : '1',
+                          'example' : ['bridge-mcrouter 1']},
+                    'bridge-mcsnoop' :
+                        { 'help' : 'set multicast snooping',
+                          'default' : '1',
+                          'example' : ['bridge-mcsnoop 1']},
+                    'bridge-mcsqc' :
+                        { 'help' : 'set multicast startup query count',
+                          'default' : '2',
+                          'example' : ['bridge-mcsqc 2']},
+                    'bridge-mcqifaddr' :
+                        { 'help' : 'set multicast query to use ifaddr',
+                          'default' : '0',
+                          'example' : ['bridge-mcqifaddr 0']},
+                    'bridge-mcquerier' :
+                        { 'help' : 'set multicast querier',
+                          'default' : '0',
+                          'example' : ['bridge-mcquerier 0']},
+                    'bridge-hashel' :
+                        { 'help' : 'set hash elasticity',
+                          'default' : '4096',
+                          'example' : ['bridge-hashel 4096']},
+                    'bridge-hashmax' :
+                        { 'help' : 'set hash max',
+                          'default' : '4096',
+                          'example' : ['bridge-hashmax 4096']},
+                    'bridge-mclmi' :
+                        { 'help' : 'set multicast last member interval (in secs)',
+                          'default' : '1',
+                          'example' : ['bridge-mclmi 1']},
+                    'bridge-mcmi' :
+                        { 'help' : 'set multicast membership interval (in secs)',
+                          'default' : '260',
+                          'example' : ['bridge-mcmi 260']},
+                    'bridge-mcqpi' :
+                        { 'help' : 'set multicast querier interval (in secs)',
+                          'default' : '255',
+                          'example' : ['bridge-mcqpi 255']},
+                    'bridge-mcqi' :
+                        { 'help' : 'set multicast query interval (in secs)',
+                          'default' : '125',
+                          'example' : ['bridge-mcqi 125']},
+                    'bridge-mcqri' :
+                        { 'help' : 'set multicast query response interval (in secs)',
+                          'default' : '10',
+                          'example' : ['bridge-mcqri 10']},
+                    'bridge-mcsqi' :
+                        { 'help' : 'set multicast startup query interval (in secs)',
+                          'default' : '31',
+                          'example' : ['bridge-mcsqi 31']},
+                    'bridge-mcqv4src' :
+                        { 'help' : 'set per VLAN v4 multicast querier source address',
+                          'compat' : True,
+                          'example' : ['bridge-mcqv4src 100=172.16.100.1 101=172.16.101.1']},
+                    'bridge-portmcrouter' :
+                        { 'help' : 'set port multicast routers',
+                          'default' : '1',
+                          'example' : ['under the bridge: bridge-portmcrouter swp1=1 swp2=1',
+                                       'under the port: bridge-portmcrouter 1']},
+                    'bridge-portmcfl' :
+                        { 'help' : 'port multicast fast leave.',
+                          'default' : '0',
+                          'example' : ['under the bridge: bridge-portmcfl swp1=0 swp2=0',
+                                       'under the port: bridge-portmcfl 0']},
+                    'bridge-waitport' :
+                        { 'help' : 'wait for a max of time secs for the' +
+                                ' specified ports to become available,' +
+                                'if no ports are specified then those' +
+                                ' specified on bridge-ports will be' +
+                                ' used here. Specifying no ports here ' +
+                                'should not be used if we are using ' +
+                                'regex or \"all\" on bridge_ports,' +
+                                'as it wouldnt work.',
+                          'default' : '0',
+                          'example' : ['bridge-waitport 4 swp1 swp2']},
+                    'bridge-maxwait' :
+                        { 'help' : 'forces to time seconds the maximum time ' +
+                                'that the Debian bridge setup  scripts will ' +
+                                'wait for the bridge ports to get to the ' +
+                                'forwarding status, doesn\'t allow factional ' +
+                                'part. If it is equal to 0 then no waiting' +
+                                ' is done',
+                          'default' : '0',
+                          'example' : ['bridge-maxwait 3']},
+                    'bridge-vids' :
+                        { 'help' : 'bridge port vids. Can be specified ' +
+                                   'under the bridge or under the port. ' +
+                                   'If specified under the bridge the ports ' +
+                                   'inherit it unless overridden by a ' +
+                                   'bridge-vids attribuet under the port',
+                          'example' : ['bridge-vids 4000',
+                                       'bridge-vids 2000 2200-3000']},
+                    'bridge-pvid' :
+                        { 'help' : 'bridge port pvid. Must be specified under' +
+                                   ' the bridge port',
+                          'example' : ['bridge-pvid 1']},
+                    'bridge-access' :
+                        { 'help' : 'bridge port access vlan. Must be ' +
+                                   'specified under the bridge port',
+                          'example' : ['bridge-access 300']},
+                    'bridge-port-vids' :
+                        { 'help' : 'bridge vlans',
+                          'compat': True,
+                          'example' : ['bridge-port-vids bond0=1-1000,1010-1020']},
+                    'bridge-port-pvids' :
+                        { 'help' : 'bridge port vlans',
+                          'compat': True,
+                          'example' : ['bridge-port-pvids bond0=100 bond1=200']},
+                     }}
+
+    def __init__(self, *args, **kargs):
+        moduleBase.__init__(self, *args, **kargs)
+        self.ipcmd = None
+        self.name = self.__class__.__name__
+        self.brctlcmd = None
+        self._running_vidinfo = {}
+        self._running_vidinfo_valid = False
+        self._resv_vlan_range =  self._get_reserved_vlan_range()
+        self.logger.debug('%s: using reserved vlan range %s'
+                  %(self.__class__.__name__, str(self._resv_vlan_range)))
+
+    def _is_bridge(self, ifaceobj):
+        if ifaceobj.get_attr_value_first('bridge-ports'):
+            return True
+        return False
+
+    def _is_bridge_port(self, ifaceobj):
+        if self.brctlcmd.is_bridge_port(ifaceobj.name):
+            return True
+        return False
+
+    def get_dependent_ifacenames(self, ifaceobj, ifacenames_all=None):
+        if not self._is_bridge(ifaceobj):
+            return None
+        if ifaceobj.link_type != ifaceLinkType.LINK_NA:
+           ifaceobj.link_type = ifaceLinkType.LINK_MASTER
+        ifaceobj.link_kind |= ifaceLinkKind.BRIDGE
+        ifaceobj.role |= ifaceRole.MASTER
+        ifaceobj.dependency_type = ifaceDependencyType.MASTER_SLAVE
+        return self.parse_port_list(ifaceobj.get_attr_value_first(
+                                    'bridge-ports'), ifacenames_all)
+
+    def get_dependent_ifacenames_running(self, ifaceobj):
+        self._init_command_handlers()
+        if not self.brctlcmd.bridge_exists(ifaceobj.name):
+            return None
+        return self.brctlcmd.get_bridge_ports(ifaceobj.name)
+
+    def _get_bridge_port_list(self, ifaceobj):
+
+        # port list is also available in the previously
+        # parsed dependent list. Use that if available, instead
+        # of parsing port expr again
+        port_list = ifaceobj.lowerifaces
+        if port_list:
+            return port_list
+        ports = ifaceobj.get_attr_value_first('bridge-ports')
+        if ports:
+            return self.parse_port_list(ports)
+        else:
+            return None
+
+    def _process_bridge_waitport(self, ifaceobj, portlist):
+        waitport_value = ifaceobj.get_attr_value_first('bridge-waitport')
+        if not waitport_value: return
+        try:
+            waitportvals = re.split(r'[\s\t]\s*', waitport_value, 1)
+            if not waitportvals: return
+            try:
+                waitporttime = int(waitportvals[0])
+            except:
+                self.log_warn('%s: invalid waitport value \'%s\''
+                        %(ifaceobj.name, waitporttime))
+                return
+            if waitporttime <= 0: return
+            try:
+                waitportlist = self.parse_port_list(waitportvals[1])
+            except IndexError, e:
+                # ignore error and use all bridge ports
+                waitportlist = portlist
+                pass
+            if not waitportlist: return
+            self.logger.info('%s: waiting for ports %s to exist ...'
+                    %(ifaceobj.name, str(waitportlist)))
+            starttime = time.time()
+            while ((time.time() - starttime) < waitporttime):
+                if all([False for p in waitportlist
+                        if not self.ipcmd.link_exists(p)]):
+                    break;
+                time.sleep(1)
+        except Exception, e:
+            self.log_warn('%s: unable to process waitport: %s'
+                    %(ifaceobj.name, str(e)))
+
+    def _ports_enable_disable_ipv6(self, ports, enable='1'):
+        for p in ports:
+            try:
+                self.write_file('/proc/sys/net/ipv6/conf/%s' %p +
+                                '/disable_ipv6', enable)
+            except Exception, e:
+                self.logger.info(str(e))
+                pass
+
+    def _add_ports(self, ifaceobj):
+        bridgeports = self._get_bridge_port_list(ifaceobj)
+        runningbridgeports = []
+        removedbridgeports = []
+
+        self.ipcmd.batch_start()
+        self._process_bridge_waitport(ifaceobj, bridgeports)
+        self.ipcmd.batch_start()
+        # Delete active ports not in the new port list
+        if not self.PERFMODE:
+            runningbridgeports = self.brctlcmd.get_bridge_ports(ifaceobj.name)
+            if runningbridgeports:
+                for bport in runningbridgeports:
+                    if not bridgeports or bport not in bridgeports:
+                        self.ipcmd.link_set(bport, 'nomaster')
+                        removedbridgeports.append(bport)
+            else:
+                runningbridgeports = []
+        if not bridgeports:
+            self.ipcmd.batch_commit()
+            return
+        err = 0
+        for bridgeport in Set(bridgeports).difference(Set(runningbridgeports)):
+            try:
+                if not self.DRYRUN and not self.ipcmd.link_exists(bridgeport):
+                    self.log_warn('%s: bridge port %s does not exist'
+                                   %(ifaceobj.name, bridgeport))
+                    err += 1
+                    continue
+                hwaddress = self.ipcmd.link_get_hwaddress(bridgeport)
+                if not self._valid_ethaddr(hwaddress):
+                    self.log_warn('%s: skipping port %s, ' %(ifaceobj.name,
+                                  bridgeport) + 'invalid ether addr %s'
+                                  %hwaddress)
+                    continue
+                self.ipcmd.link_set(bridgeport, 'master', ifaceobj.name)
+                self.ipcmd.addr_flush(bridgeport)
+            except Exception, e:
+                self.logger.error(str(e))
+                pass
+        try:
+            self.ipcmd.batch_commit()
+        except Exception, e:
+            self.logger.error(str(e))
+            pass
+
+        # enable ipv6 for ports that were removed
+        self._ports_enable_disable_ipv6(removedbridgeports, '0')
+        if err:
+            self.log_error('bridge configuration failed (missing ports)')
+
+
+    def _process_bridge_maxwait(self, ifaceobj, portlist):
+        maxwait = ifaceobj.get_attr_value_first('bridge-maxwait')
+        if not maxwait: return
+        try:
+            maxwait = int(maxwait)
+        except:
+            self.log_warn('%s: invalid maxwait value \'%s\'' %(ifaceobj.name,
+                    maxwait))
+            return
+        if not maxwait: return
+        self.logger.info('%s: waiting for ports to go to fowarding state ..'
+                %ifaceobj.name)
+        try:
+            starttime = time.time()
+            while ((time.time() - starttime) < maxwait):
+                if all([False for p in portlist
+                    if self.read_file_oneline(
+                            '/sys/class/net/%s/brif/%s/state'
+                            %(ifaceobj.name, p)) != '3']):
+                    break;
+                time.sleep(1)
+        except Exception, e:
+            self.log_warn('%s: unable to process maxwait: %s'
+                    %(ifaceobj.name, str(e)))
+
+    def _ints_to_ranges(self, ints):
+        for a, b in itertools.groupby(enumerate(ints), lambda (x, y): y - x):
+            b = list(b)
+            yield b[0][1], b[-1][1]
+
+    def _ranges_to_ints(self, rangelist):
+        """ returns expanded list of integers given set of string ranges
+        example: ['1', '2-4', '6'] returns [1, 2, 3, 4, 6]
+        """
+        result = []
+        for part in rangelist:
+            if '-' in part:
+                a, b = part.split('-')
+                a, b = int(a), int(b)
+                result.extend(range(a, b + 1))
+            else:
+                a = int(part)
+                result.append(a)
+        return result
+
+    def _diff_vids(self, vids1, vids2):
+        vids_to_add = None
+        vids_to_del = None
+
+        vids1_ints = self._ranges_to_ints(vids1)
+        vids2_ints = self._ranges_to_ints(vids2)
+        vids1_diff = Set(vids1_ints).difference(vids2_ints)
+        vids2_diff = Set(vids2_ints).difference(vids1_ints)
+        if vids1_diff:
+            vids_to_add = ['%d' %start if start == end else '%d-%d' %(start, end)
+                        for start, end in self._ints_to_ranges(vids1_diff)]
+        if vids2_diff:
+            vids_to_del = ['%d' %start if start == end else '%d-%d' %(start, end)
+                        for start, end in self._ints_to_ranges(vids2_diff)]
+        return (vids_to_del, vids_to_add)
+
+    def _compare_vids(self, vids1, vids2):
+        """ Returns true if the vids are same else return false """
+
+        vids1_ints = self._ranges_to_ints(vids1)
+        vids2_ints = self._ranges_to_ints(vids2)
+        if Set(vids1_ints).symmetric_difference(vids2_ints):
+            return False
+        else:
+            return True
+
+    def _set_bridge_mcqv4src_compat(self, ifaceobj):
+        #
+        # Sets old style igmp querier
+        #
+        attrval = ifaceobj.get_attr_value_first('bridge-mcqv4src')
+        if attrval:
+            running_mcqv4src = {}
+            if not self.PERFMODE:
+                running_mcqv4src = self.brctlcmd.get_mcqv4src(ifaceobj.name)
+            mcqs = {}
+            srclist = attrval.split()
+            for s in srclist:
+                k, v = s.split('=')
+                mcqs[k] = v
+
+            k_to_del = Set(running_mcqv4src.keys()).difference(mcqs.keys())
+            for v in k_to_del:
+                self.brctlcmd.del_mcqv4src(ifaceobj.name, v)
+            for v in mcqs.keys():
+                self.brctlcmd.set_mcqv4src(ifaceobj.name, v, mcqs[v])
+
+    def _get_running_vidinfo(self):
+        if self._running_vidinfo_valid:
+            return self._running_vidinfo
+        self._running_vidinfo = {}
+        if not self.PERFMODE:
+            self._running_vidinfo = self.ipcmd.bridge_port_vids_get_all()
+        self._running_vidinfo_valid = True
+        return self._running_vidinfo
+
+    def _flush_running_vidinfo(self):
+        self._running_vidinfo = {}
+        self._running_vidinfo_valid = False
+
+    def _set_bridge_vidinfo_compat(self, ifaceobj):
+        #
+        # Supports old style vlan vid info format
+        # for compatibility
+        #
+
+        # Handle bridge vlan attrs
+        running_vidinfo = self._get_running_vidinfo()
+
+        # Install pvids
+        attrval = ifaceobj.get_attr_value_first('bridge-port-pvids')
+        if attrval:
+            portlist = self.parse_port_list(attrval)
+            if not portlist:
+                self.log_warn('%s: could not parse \'%s %s\''
+                              %(ifaceobj.name, attrname, attrval))
+                return
+            for p in portlist:
+                try:
+                    (port, pvid) = p.split('=')
+                    running_pvid = running_vidinfo.get(port, {}).get('pvid')
+                    if running_pvid:
+                        if running_pvid == pvid:
+                            continue
+                        else:
+                            self.ipcmd.bridge_port_pvid_del(port, running_pvid)
+                    self.ipcmd.bridge_port_pvid_add(port, pvid)
+                except Exception, e:
+                    self.log_warn('%s: failed to set pvid `%s` (%s)'
+                            %(ifaceobj.name, p, str(e)))
+
+        # install port vids
+        attrval = ifaceobj.get_attr_value_first('bridge-port-vids')
+        if attrval:
+            portlist = self.parse_port_list(attrval)
+            if not portlist:
+                self.log_warn('%s: could not parse \'%s %s\''
+                          %(ifaceobj.name, attrname, attrval))
+                return
+            for p in portlist:
+                try:
+                    (port, val) = p.split('=')
+                    vids = val.split(',')
+                    if running_vidinfo.get(port):
+                        (vids_to_del, vids_to_add) = \
+                                self._diff_vids(vids,
+                                running_vidinfo.get(port).get('vlan'))
+                        if vids_to_del:
+                            self.ipcmd.bridge_port_vids_del(port, vids_to_del)
+                        if vids_to_add:
+                            self.ipcmd.bridge_port_vids_add(port, vids_to_add)
+                    else:
+                        self.ipcmd.bridge_port_vids_add(port, vids)
+                except Exception, e:
+                    self.log_warn('%s: failed to set vid `%s` (%s)'
+                        %(ifaceobj.name, p, str(e)))
+
+        # install vids
+        # XXX: Commenting out this code for now because it was decided
+        # that this is not needed
+        #attrval = ifaceobj.get_attr_value_first('bridge-vids')
+        #if attrval:
+        #    vids = re.split(r'[\s\t]\s*', attrval)
+        #    if running_vidinfo.get(ifaceobj.name):
+        #        (vids_to_del, vids_to_add) = \
+        #                self._diff_vids(vids,
+        #                    running_vidinfo.get(ifaceobj.name).get('vlan'))
+        #        if vids_to_del:
+        #            self.ipcmd.bridge_vids_del(ifaceobj.name, vids_to_del)
+        #        if vids_to_add:
+        #            self.ipcmd.bridge_vids_add(ifaceobj.name, vids_to_add)
+        #    else:
+        #        self.ipcmd.bridge_vids_add(ifaceobj.name, vids)
+        #else:
+        #    running_vids = running_vidinfo.get(ifaceobj.name)
+        #    if running_vids:
+        #        self.ipcmd.bridge_vids_del(ifaceobj.name, running_vids)
+
+    def _apply_bridge_settings(self, ifaceobj):
+        try:
+            stp = ifaceobj.get_attr_value_first('bridge-stp')
+            if stp:
+                self.brctlcmd.set_stp(ifaceobj.name, stp)
+            else:
+                # If stp not specified and running stp state on, set it to off
+                running_stp_state = self.read_file_oneline(
+                       '/sys/class/net/%s/bridge/stp_state' %ifaceobj.name)
+                if running_stp_state and running_stp_state != '0':
+                   self.brctlcmd.set_stp(ifaceobj.name, 'no')
+
+            if ifaceobj.get_attr_value_first('bridge-vlan-aware') == 'yes':
+               self.write_file('/sys/class/net/%s/bridge/vlan_filtering'
+                       %ifaceobj.name, '1')
+            # Use the brctlcmd bulk set method: first build a dictionary
+            # and then call set
+            bridgeattrs = { k:v for k,v in
+                             {'ageing' :
+                                ifaceobj.get_attr_value_first('bridge-ageing'),
+                              'bridgeprio' :
+                                ifaceobj.get_attr_value_first(
+                                                        'bridge-bridgeprio'),
+                              'fd' :
+                                ifaceobj.get_attr_value_first('bridge-fd'),
+                              'gcint' :
+                                ifaceobj.get_attr_value_first('bridge-gcint'),
+                              'hello' :
+                                ifaceobj.get_attr_value_first('bridge-hello'),
+                              'maxage' :
+                                ifaceobj.get_attr_value_first('bridge-maxage'),
+                              'mclmc' :
+                                ifaceobj.get_attr_value_first('bridge-mclmc'),
+                              'mcrouter' :
+                                ifaceobj.get_attr_value_first(
+                                                            'bridge-mcrouter'),
+                              'mcsnoop' :
+                                ifaceobj.get_attr_value_first('bridge-mcsnoop'),
+                              'mcsqc' :
+                                ifaceobj.get_attr_value_first('bridge-mcsqc'),
+                              'mcqifaddr' :
+                                ifaceobj.get_attr_value_first(
+                                                            'bridge-mcqifaddr'),
+                              'mcquerier' :
+                                ifaceobj.get_attr_value_first(
+                                                            'bridge-mcquerier'),
+                              'hashel' :
+                                ifaceobj.get_attr_value_first('bridge-hashel'),
+                              'hashmax' :
+                                ifaceobj.get_attr_value_first('bridge-hashmax'),
+                              'mclmi' :
+                                ifaceobj.get_attr_value_first('bridge-mclmi'),
+                              'mcmi' :
+                                ifaceobj.get_attr_value_first('bridge-mcmi'),
+                              'mcqpi' :
+                                ifaceobj.get_attr_value_first('bridge-mcqpi'),
+                              'mcqi' :
+                                ifaceobj.get_attr_value_first('bridge-mcqi'),
+                              'mcqri' :
+                                ifaceobj.get_attr_value_first('bridge-mcqri'),
+                              'mcsqi' :
+                                ifaceobj.get_attr_value_first('bridge-mcsqi')
+                               }.items()
+                            if v }
+            if bridgeattrs:
+                self.brctlcmd.set_bridge_attrs(ifaceobj.name, bridgeattrs)
+            portattrs = {}
+            for attrname, dstattrname in {'bridge-pathcosts' : 'pathcost',
+                                'bridge-portprios' : 'portprio',
+                                'bridge-portmcrouter' : 'portmcrouter',
+                                'bridge-portmcfl' : 'portmcfl'}.items():
+                attrval = ifaceobj.get_attr_value_first(attrname)
+                if not attrval:
+                    continue
+                portlist = self.parse_port_list(attrval)
+                if not portlist:
+                    self.log_warn('%s: could not parse \'%s %s\''
+                         %(ifaceobj.name, attrname, attrval))
+                    continue
+                for p in portlist:
+                    try:
+                        (port, val) = p.split('=')
+                        if not portattrs.get(port):
+                            portattrs[port] = {}
+                        portattrs[port].update({dstattrname : val})
+                    except Exception, e:
+                        self.log_warn('%s: could not parse %s (%s)'
+                                    %(ifaceobj.name, attrname, str(e)))
+            for port, attrdict in portattrs.iteritems():
+                try:
+                    self.brctlcmd.set_bridgeport_attrs(ifaceobj.name, port,
+                                                       attrdict)
+                except Exception, e:
+                    self.log_warn('%s: %s', str(e))
+                    pass
+            self._set_bridge_vidinfo_compat(ifaceobj)
+            self._set_bridge_mcqv4src_compat(ifaceobj)
+            self._process_bridge_maxwait(ifaceobj,
+                    self._get_bridge_port_list(ifaceobj))
+        except Exception, e:
+            self.log_warn(str(e))
+
+    def _check_vids(self, ifaceobj, vids):
+        ret = True
+        for v in vids:
+            if '-' in v:
+                va, vb = v.split('-')
+                va, vb = int(va), int(vb)
+                if (self._handle_reserved_vlan(va, ifaceobj.name) or
+                    self._handle_reserved_vlan(vb, ifaceobj.name)):
+                    ret = False
+            else:
+                va = int(v)
+                if self._handle_reserved_vlan(va, ifaceobj.name):
+                   ret = False
+        return ret
+         
+    def _apply_bridge_vids(self, bportifaceobj, vids, running_vids, isbridge):
+        try:
+            if not self._check_vids(bportifaceobj, vids):
+               return
+            if running_vids:
+                (vids_to_del, vids_to_add) = \
+                    self._diff_vids(vids, running_vids)
+                if vids_to_del:
+                    self.ipcmd.bridge_vids_del(bportifaceobj.name,
+                                               vids_to_del, isbridge)
+                if vids_to_add:
+                    self.ipcmd.bridge_vids_add(bportifaceobj.name,
+                                               vids_to_add, isbridge)
+            else:
+                self.ipcmd.bridge_vids_add(bportifaceobj.name, vids, isbridge)
+        except Exception, e:
+                self.log_warn('%s: failed to set vid `%s` (%s)'
+                        %(bportifaceobj.name, str(vids), str(e)))
+
+    def _apply_bridge_port_pvids(self, bportifaceobj, pvid, running_pvid):
+        # Install pvids
+        try:
+            if running_pvid:
+                if running_pvid != pvid:
+                    self.ipcmd.bridge_port_pvid_del(bportifaceobj.name,
+                                                    running_pvid)
+                self.ipcmd.bridge_port_pvid_add(bportifaceobj.name, pvid)
+            else:
+                self.ipcmd.bridge_port_pvid_add(bportifaceobj.name, pvid)
+        except Exception, e:
+            self.log_warn('%s: failed to set pvid `%s` (%s)'
+                          %(bportifaceobj.name, pvid, str(e)))
+
+    def _apply_bridge_vids_and_pvid(self, bportifaceobj, vids, running_vids,
+                                    pvid, running_pvid, isbridge):
+        """ This method is a combination of methods _apply_bridge_vids and
+            _apply_bridge_port_pvids above. A combined function is
+            found necessary to do the deletes first and the adds later
+            because kernel does honor vid info flags during deletes.
+
+        """
+
+        try:
+            if not self._check_vids(bportifaceobj, vids):
+               return
+
+            vids_to_del = []
+            vids_to_add = vids
+            pvid_to_del = None
+            pvid_to_add = pvid if pvid else '1'
+
+            if running_vids:
+                (vids_to_del, vids_to_add) = \
+                    self._diff_vids(vids, running_vids)
+
+            if running_pvid:
+                if running_pvid != pvid:
+                    pvid_to_del = running_pvid
+
+            if (pvid_to_del and (pvid_to_del in vids) and
+                (pvid_to_del not in vids_to_add)):
+                # kernel deletes dont take into account
+                # bridge vid flags and its possible that
+                # the pvid deletes we do end up deleting
+                # the vids. Be proactive and add the pvid
+                # to the vid add list if it is in the vids
+                # and not already part of vids_to_add.
+                # This helps with a small corner case:
+                #   - running
+                #       pvid 100
+                #       vid 101 102
+                #   - new change is going to move the state to
+                #       pvid 101
+                #       vid 100 102
+                vids_to_add.append(pvid_to_del)
+        except Exception, e:
+            self.log_warn('%s: failed to process vids/pvids'
+                          %bportifaceobj.name + ' vids = %s' %str(vids) +
+                          'pvid = %s ' %pvid + '(%s)' %str(e))
+        try:
+            if vids_to_del:
+               self.ipcmd.bridge_vids_del(bportifaceobj.name,
+                                          vids_to_del, isbridge)
+        except Exception, e:
+                self.log_warn('%s: failed to del vid `%s` (%s)'
+                        %(bportifaceobj.name, str(vids_to_del), str(e)))
+
+        try:
+            if pvid_to_del:
+               self.ipcmd.bridge_port_pvid_del(bportifaceobj.name,
+                                               pvid_to_del)
+        except Exception, e:
+                self.log_warn('%s: failed to del pvid `%s` (%s)'
+                        %(bportifaceobj.name, pvid_to_del, str(e)))
+
+        try:
+            if vids_to_add:
+               self.ipcmd.bridge_vids_add(bportifaceobj.name,
+                                           vids_to_add, isbridge)
+        except Exception, e:
+                self.log_warn('%s: failed to set vid `%s` (%s)'
+                        %(bportifaceobj.name, str(vids_to_add), str(e)))
+
+        try:
+            self.ipcmd.bridge_port_pvid_add(bportifaceobj.name, pvid_to_add)
+        except Exception, e:
+                self.log_warn('%s: failed to set pvid `%s` (%s)'
+                        %(bportifaceobj.name, pvid_to_add, str(e)))
+
+    def _apply_bridge_vlan_aware_port_settings_all(self, bportifaceobj,
+                                                   bridge_vids=None,
+                                                   bridge_pvid=None):
+        running_vidinfo = self._get_running_vidinfo()
+        vids = None
+        pvids = None
+        vids_final = []
+        pvid_final = None
+        bport_access = bportifaceobj.get_attr_value_first('bridge-access')
+        if bport_access:
+            vids = re.split(r'[\s\t]\s*', bport_access)
+            pvids = vids
+        else:
+            bport_vids = bportifaceobj.get_attr_value_first('bridge-vids')
+            if bport_vids:
+                vids = re.split(r'[\s\t,]\s*', bport_vids)
+
+            bport_pvids = bportifaceobj.get_attr_value_first('bridge-pvid')
+            if bport_pvids:
+                pvids = re.split(r'[\s\t]\s*', bport_pvids)
+
+        if vids:
+            vids_final =  vids
+        elif bridge_vids:
+            vids_final = bridge_vids
+
+        if pvids:
+            pvid_final = pvids[0]
+        elif bridge_pvid:
+            pvid_final = bridge_pvid
+
+        self._apply_bridge_vids_and_pvid(bportifaceobj, vids_final,
+                running_vidinfo.get(bportifaceobj.name, {}).get('vlan'),
+                pvid_final,
+                running_vidinfo.get(bportifaceobj.name, {}).get('pvid'),
+                False)
+
+    def _apply_bridge_port_settings(self, bportifaceobj, bridgename=None,
+                                    bridgeifaceobj=None):
+        if not bridgename and bridgeifaceobj:
+            bridgename = bridgeifaceobj.name
+        # Set other stp and igmp attributes
+        portattrs = {}
+        for attrname, dstattrname in {
+            'bridge-pathcosts' : 'pathcost',
+            'bridge-portprios' : 'portprio',
+            'bridge-portmcrouter' : 'portmcrouter',
+            'bridge-portmcfl' : 'portmcfl'}.items():
+            attrval = bportifaceobj.get_attr_value_first(attrname)
+            if not attrval:
+                # Check if bridge has that attribute
+                #if bridgeifaceobj:
+                #    attrval = bridgeifaceobj.get_attr_value_first(attrname)
+                #    if not attrval:
+                #        continue
+                #else:
+                continue
+            portattrs[dstattrname] = attrval
+        try:
+            self.brctlcmd.set_bridgeport_attrs(bridgename,
+                            bportifaceobj.name, portattrs)
+        except Exception, e:
+            self.log_warn(str(e))
+
+    def _apply_bridge_port_settings_all(self, ifaceobj,
+                                        ifaceobj_getfunc=None):
+        err = False
+        bridge_vlan_aware = ifaceobj.get_attr_value_first(
+                                           'bridge-vlan-aware')
+        if bridge_vlan_aware and bridge_vlan_aware == 'yes':
+           bridge_vlan_aware = True
+        else:
+           bridge_vlan_aware = False
+
+        if (ifaceobj.get_attr_value_first('bridge-port-vids') and
+                ifaceobj.get_attr_value_first('bridge-port-pvids')):
+            # Old style bridge port vid info
+            # skip new style setting on ports
+            return
+        self.logger.info('%s: applying bridge configuration '
+                         %ifaceobj.name + 'specific to ports')
+
+        bridge_vids = ifaceobj.get_attr_value_first('bridge-vids')
+        if bridge_vids:
+           bridge_vids = re.split(r'[\s\t,]\s*', bridge_vids)
+        else:
+           bridge_vids = None
+
+        bridge_pvid = ifaceobj.get_attr_value_first('bridge-pvid')
+        if bridge_pvid:
+           bridge_pvid = re.split(r'[\s\t]\s*', bridge_pvid)[0]
+        else:
+           bridge_pvid = None
+
+        bridgeports = self._get_bridge_port_list(ifaceobj)
+        if not bridgeports:
+           self.logger.debug('%s: cannot find bridgeports' %ifaceobj.name)
+           return
+        for bport in bridgeports:
+            # Use the brctlcmd bulk set method: first build a dictionary
+            # and then call set
+            if not self.ipcmd.bridge_port_exists(ifaceobj.name, bport):
+                self.logger.info('%s: skipping bridge config' %ifaceobj.name +
+                        ' for port %s (missing port)' %bport)
+                continue
+            self.logger.info('%s: processing bridge config for port %s'
+                             %(ifaceobj.name, bport))
+            bportifaceobjlist = ifaceobj_getfunc(bport)
+            if not bportifaceobjlist:
+               continue
+            for bportifaceobj in bportifaceobjlist:
+                # Dont process bridge port if it already has been processed
+                if (bportifaceobj.module_flags.get(self.name,0x0) & \
+                    bridgeFlags.PORT_PROCESSED):
+                    continue
+                try:
+                    # Add attributes specific to the vlan aware bridge
+                    if bridge_vlan_aware:
+                        self._apply_bridge_vlan_aware_port_settings_all(
+                                bportifaceobj, bridge_vids, bridge_pvid)
+                        self._apply_bridge_port_settings(bportifaceobj,
+                                                 bridgeifaceobj=ifaceobj)
+                except Exception, e:
+                    err = True
+                    self.logger.warn('%s: %s' %(ifaceobj.name, str(e)))
+                    pass
+        if err:
+           raise Exception('%s: errors applying port settings' %ifaceobj.name)
+
+    def _up(self, ifaceobj, ifaceobj_getfunc=None):
+        # Check if bridge port
+        bridgename = self.ipcmd.bridge_port_get_bridge_name(ifaceobj.name)
+        if bridgename:
+           if self.ipcmd.bridge_is_vlan_aware(bridgename):
+              bridge_vids = self._get_bridge_vids(bridgename,
+                                                  ifaceobj_getfunc)
+              bridge_pvid = self._get_bridge_pvid(bridgename,
+                                                   ifaceobj_getfunc)
+              self._apply_bridge_vlan_aware_port_settings_all(ifaceobj,
+                                                              bridge_vids,
+                                                              bridge_pvid)
+           self._apply_bridge_port_settings(ifaceobj, bridgename=bridgename)
+           ifaceobj.module_flags[self.name] = ifaceobj.module_flags.setdefault(self.name,0) | \
+                                              bridgeFlags.PORT_PROCESSED
+           return
+        if not self._is_bridge(ifaceobj):
+            return
+        err = False
+        errstr = ''
+        running_ports = ''
+        try:
+            if not self.PERFMODE:
+                if not self.ipcmd.link_exists(ifaceobj.name):
+                   self.ipcmd.link_create(ifaceobj.name, 'bridge')
+            else:
+                self.ipcmd.link_create(ifaceobj.name, 'bridge')
+        except Exception, e:
+            raise Exception(str(e))
+        try:
+            self._add_ports(ifaceobj)
+        except Exception, e:
+            err = True
+            errstr = str(e)
+            pass
+
+        try:
+            self._apply_bridge_settings(ifaceobj)
+        except Exception, e:
+            err = True
+            errstr = str(e)
+            pass
+
+        try:
+            running_ports = self.brctlcmd.get_bridge_ports(ifaceobj.name)
+            if not running_ports:
+               return
+            # disable ipv6 for ports that were added to bridge
+            self._ports_enable_disable_ipv6(running_ports, '1')
+            self._apply_bridge_port_settings_all(ifaceobj,
+                            ifaceobj_getfunc=ifaceobj_getfunc)
+        except Exception, e:
+            err = True
+            errstr = str(e)
+            pass
+            #self._flush_running_vidinfo()
+        finally:
+            if ifaceobj.link_type != ifaceLinkType.LINK_NA:
+                for p in running_ports:
+                    try:
+                        rtnetlink_api.rtnl_api.link_set(p, "up")
+                    except Exception, e:
+                        self.logger.debug('%s: %s: link set up (%s)'
+                                          %(ifaceobj.name, p, str(e)))
+                        pass
+
+            if ifaceobj.addr_method == 'manual':
+               rtnetlink_api.rtnl_api.link_set(ifaceobj.name, "up")
+        if err:
+            raise Exception(errstr)
+
+    def _down(self, ifaceobj, ifaceobj_getfunc=None):
+        try:
+            if ifaceobj.get_attr_value_first('bridge-ports'):
+                ports = self.brctlcmd.get_bridge_ports(ifaceobj.name)
+                self.brctlcmd.delete_bridge(ifaceobj.name)
+                if ports:
+                    self._ports_enable_disable_ipv6(ports, '0')
+                    if ifaceobj.link_type != ifaceLinkType.LINK_NA:
+                        map(lambda p: rtnetlink_api.rtnl_api.link_set(p,
+                                    "down"), ports)
+        except Exception, e:
+            self.log_error(str(e))
+
+    def _query_running_vidinfo_compat(self, ifaceobjrunning, ports):
+        running_attrs = {}
+        running_vidinfo = self._get_running_vidinfo()
+        if ports:
+            running_bridge_port_vids = ''
+            for p in ports:
+                try:
+                    running_vids = running_vidinfo.get(p, {}).get('vlan')
+                    if running_vids:
+                        running_bridge_port_vids += ' %s=%s' %(p,
+                                                      ','.join(running_vids))
+                except Exception:
+                    pass
+            running_attrs['bridge-port-vids'] = running_bridge_port_vids
+
+            running_bridge_port_pvids = ''
+            for p in ports:
+                try:
+                    running_pvids = running_vidinfo.get(p, {}).get('pvid')
+                    if running_pvids:
+                        running_bridge_port_pvids += ' %s=%s' %(p,
+                                                        running_pvids)
+                except Exception:
+                    pass
+            running_attrs['bridge-port-pvids'] = running_bridge_port_pvids
+
+        running_bridge_vids = running_vidinfo.get(ifaceobjrunning.name,
+                                                  {}).get('vlan')
+        if running_bridge_vids:
+            running_attrs['bridge-vids'] = ','.join(running_bridge_vids)
+        return running_attrs
+
+    def _query_running_vidinfo(self, ifaceobjrunning, ifaceobj_getfunc,
+                               bridgeports=None):
+        running_attrs = {}
+        running_vidinfo = self._get_running_vidinfo()
+        if not running_vidinfo:
+           return running_attrs
+
+        # 'bridge-vids' under the bridge is all about 'vids' on the port.
+        # so query the ports
+        running_bridgeport_vids = []
+        running_bridgeport_pvids = []
+        for bport in bridgeports:
+            vids = running_vidinfo.get(bport, {}).get('vlan')
+            if vids:
+                running_bridgeport_vids.append(' '.join(vids))
+            pvids = running_vidinfo.get(bport, {}).get('pvid')
+            if pvids:
+                running_bridgeport_pvids.append(pvids[0])
+
+        bridge_vids = None
+        if running_bridgeport_vids: 
+           (vidval, freq) = Counter(running_bridgeport_vids).most_common()[0]
+           if freq == len(bridgeports):
+              running_attrs['bridge-vids'] = vidval
+              bridge_vids = vidval.split()
+
+        bridge_pvid = None
+        if running_bridgeport_pvids:
+           (vidval, freq) = Counter(running_bridgeport_pvids).most_common()[0]
+           if freq == len(bridgeports) and vidval != '1':
+              running_attrs['bridge-pvid'] = vidval
+              bridge_pvid = vidval.split()
+
+        # Go through all bridge ports and find their vids
+        for bport in bridgeports:
+            bportifaceobj = ifaceobj_getfunc(bport)
+            if not bportifaceobj:
+               continue
+            bport_vids = None
+            bport_pvids = None
+            vids = running_vidinfo.get(bport, {}).get('vlan')
+            if vids and vids != bridge_vids:
+               bport_vids = vids
+            pvids = running_vidinfo.get(bport, {}).get('pvid')
+            if pvids and pvids[0] != bridge_pvid:
+               bport_pvids = pvids
+            if not bport_vids and bport_pvids and bport_pvids[0] != '1':
+               bportifaceobj[0].replace_config('bridge-access', bport_pvids[0])
+            else:
+               if bport_pvids and bport_pvids[0] != '1':
+                  bportifaceobj[0].replace_config('bridge-pvid', bport_pvids[0])
+               else:
+                  # delete any stale bridge-vids under ports
+                  bportifaceobj[0].delete_config('bridge-pvid')
+               if bport_vids:
+                  bportifaceobj[0].replace_config('bridge-vids',
+                                                  ' '.join(bport_vids))
+               else:
+                  # delete any stale bridge-vids under ports
+                  bportifaceobj[0].delete_config('bridge-vids')
+        return running_attrs
+
+    def _query_running_mcqv4src(self, ifaceobjrunning):
+        running_mcqv4src = self.brctlcmd.get_mcqv4src(ifaceobjrunning.name)
+        mcqs = ['%s=%s' %(v, i) for v, i in running_mcqv4src.items()]
+        mcqs.sort()
+        mcq = ' '.join(mcqs)
+        return mcq
+
+    def _query_running_attrs(self, ifaceobjrunning, ifaceobj_getfunc,
+                             bridge_vlan_aware=False):
+        bridgeattrdict = {}
+        userspace_stp = 0
+        ports = None
+        skip_kernel_stp_attrs = 0
+
+        if self.sysctl_get('net.bridge.bridge-stp-user-space') == '1':
+            userspace_stp = 1
+
+        tmpbridgeattrdict = self.brctlcmd.get_bridge_attrs(ifaceobjrunning.name)
+        if not tmpbridgeattrdict:
+            self.logger.warn('%s: unable to get bridge attrs'
+                    %ifaceobjrunning.name)
+            return bridgeattrdict
+
+        # Fill bridge_ports and bridge stp attributes first
+        ports = tmpbridgeattrdict.get('ports')
+        if ports:
+            bridgeattrdict['bridge-ports'] = [' '.join(ports.keys())]
+        stp = tmpbridgeattrdict.get('stp', 'no')
+        if stp != self.get_mod_subattr('bridge-stp', 'default'):
+            bridgeattrdict['bridge-stp'] = [stp]
+
+        if  stp == 'yes' and userspace_stp:
+            skip_kernel_stp_attrs = 1
+
+        # pick all other attributes
+        for k,v in tmpbridgeattrdict.items():
+            if not v:
+                continue
+            if k == 'ports' or k == 'stp':
+                continue
+
+            if skip_kernel_stp_attrs and k[:2] != 'mc':
+                # only include igmp attributes if kernel stp is off
+                continue
+            attrname = 'bridge-' + k
+            if v != self.get_mod_subattr(attrname, 'default'):
+                bridgeattrdict[attrname] = [v]
+
+        if bridge_vlan_aware:
+            bridgevidinfo = self._query_running_vidinfo(ifaceobjrunning,
+                                                        ifaceobj_getfunc,
+                                                        ports.keys())
+        else:
+            bridgevidinfo = self._query_running_vidinfo_compat(ifaceobjrunning,
+                                                               ports)
+        if bridgevidinfo:
+           bridgeattrdict.update({k : [v] for k, v in bridgevidinfo.items()
+                                  if v})
+
+        mcq = self._query_running_mcqv4src(ifaceobjrunning)
+        if mcq:
+            bridgeattrdict['bridge-mcqv4src'] = [mcq]
+
+        if skip_kernel_stp_attrs:
+            return bridgeattrdict
+
+        if ports:
+            portconfig = {'bridge-pathcosts' : '',
+                          'bridge-portprios' : ''}
+            for p, v in ports.items():
+                v = self.brctlcmd.get_pathcost(ifaceobjrunning.name, p)
+                if v and v != self.get_mod_subattr('bridge-pathcosts',
+                                                   'default'):
+                    portconfig['bridge-pathcosts'] += ' %s=%s' %(p, v)
+
+                v = self.brctlcmd.get_portprio(ifaceobjrunning.name, p)
+                if v and v != self.get_mod_subattr('bridge-portprios',
+                                                   'default'):
+                    portconfig['bridge-portprios'] += ' %s=%s' %(p, v)
+
+            bridgeattrdict.update({k : [v] for k, v in portconfig.items()
+                                    if v})
+
+        return bridgeattrdict
+
+    def _query_check_mcqv4src(self, ifaceobj, ifaceobjcurr):
+        running_mcqs = self._query_running_mcqv4src(ifaceobj)
+        attrval = ifaceobj.get_attr_value_first('bridge-mcqv4src')
+        if attrval:
+            mcqs = attrval.split()
+            mcqs.sort()
+            mcqsout = ' '.join(mcqs)
+            ifaceobjcurr.update_config_with_status('bridge-mcqv4src',
+                         running_mcqs, 1 if running_mcqs != mcqsout else 0)
+
+    def _query_check_bridge_vidinfo(self, ifaceobj, ifaceobjcurr):
+        err = 0
+        running_vidinfo = self._get_running_vidinfo()
+        attrval = ifaceobj.get_attr_value_first('bridge-port-vids')
+        if attrval:
+            running_bridge_port_vids = ''
+            portlist = self.parse_port_list(attrval)
+            if not portlist:
+                self.log_warn('%s: could not parse \'%s %s\''
+                          %(ifaceobj.name, attrname, attrval))
+                return
+            err = 0
+            for p in portlist:
+                try:
+                    (port, val) = p.split('=')
+                    vids = val.split(',')
+                    running_vids = running_vidinfo.get(port, {}).get('vlan')
+                    if running_vids:
+                        if not self._compare_vids(vids, running_vids):
+                            err += 1
+                            running_bridge_port_vids += ' %s=%s' %(port,
+                                                      ','.join(running_vids))
+                        else:
+                            running_bridge_port_vids += ' %s' %p
+                    else:
+                        err += 1
+                except Exception, e:
+                    self.log_warn('%s: failure checking vid %s (%s)'
+                        %(ifaceobj.name, p, str(e)))
+            if err:
+                ifaceobjcurr.update_config_with_status('bridge-port-vids',
+                                                 running_bridge_port_vids, 1)
+            else:
+                ifaceobjcurr.update_config_with_status('bridge-port-vids',
+                                                 attrval, 0)
+
+        attrval = ifaceobj.get_attr_value_first('bridge-port-pvids')
+        if attrval:
+            portlist = self.parse_port_list(attrval)
+            if not portlist:
+                self.log_warn('%s: could not parse \'%s %s\''
+                              %(ifaceobj.name, attrname, attrval))
+                return
+            running_bridge_port_pvids = ''
+            err = 0
+            for p in portlist:
+                try:
+                    (port, pvid) = p.split('=')
+                    running_pvid = running_vidinfo.get(port, {}).get('pvid')
+                    if running_pvid and running_pvid == pvid:
+                        running_bridge_port_pvids += ' %s' %p
+                    else:
+                        err += 1
+                        running_bridge_port_pvids += ' %s=%s' %(port,
+                                                            running_pvid)
+                except Exception, e:
+                    self.log_warn('%s: failure checking pvid %s (%s)'
+                            %(ifaceobj.name, pvid, str(e)))
+            if err:
+                ifaceobjcurr.update_config_with_status('bridge-port-pvids',
+                                                 running_bridge_port_pvids, 1)
+            else:
+                ifaceobjcurr.update_config_with_status('bridge-port-pvids',
+                                                 running_bridge_port_pvids, 0)
+
+        # XXX: No need to check for bridge-vids on the bridge
+        # This is used by the ports. The vids on the bridge
+        # come from the vlan interfaces on the bridge.
+        #
+        attrval = ifaceobj.get_attr_value_first('bridge-vids')
+        #if attrval:
+        #    vids = re.split(r'[\s\t]\s*', attrval)
+        #    running_vids = running_vidinfo.get(ifaceobj.name, {}).get('vlan')
+        #    if running_vids:
+        #        if self._compare_vids(vids, running_vids):
+        #            ifaceobjcurr.update_config_with_status('bridge-vids',
+        #                                                   attrval, 0)
+        #        else:
+        #            ifaceobjcurr.update_config_with_status('bridge-vids',
+        #                                        ','.join(running_vids), 1)
+        #    else:
+        #        ifaceobjcurr.update_config_with_status('bridge-vids', attrval,
+        #                                               1)
+        if attrval:
+            ifaceobjcurr.update_config_with_status('bridge-vids', attrval, -1)
+
+    def _query_check_bridge(self, ifaceobj, ifaceobjcurr,
+                            ifaceobj_getfunc=None):
+        if not self._is_bridge(ifaceobj):
+            return
+        if not self.brctlcmd.bridge_exists(ifaceobj.name):
+            self.logger.info('%s: bridge: does not exist' %(ifaceobj.name))
+            return
+
+        ifaceattrs = self.dict_key_subset(ifaceobj.config,
+                                          self.get_mod_attrs())
+        if not ifaceattrs:
+            return
+        try:
+            runningattrs = self.brctlcmd.get_bridge_attrs(ifaceobj.name)
+            if not runningattrs:
+               self.logger.debug('%s: bridge: unable to get bridge attrs'
+                                 %ifaceobj.name)
+               runningattrs = {}
+        except Exception, e:
+            self.logger.warn(str(e))
+            runningattrs = {}
+        filterattrs = ['bridge-vids', 'bridge-port-vids',
+                       'bridge-port-pvids']
+        for k in Set(ifaceattrs).difference(filterattrs):
+            # get the corresponding ifaceobj attr
+            v = ifaceobj.get_attr_value_first(k)
+            if not v:
+               continue
+            rv = runningattrs.get(k[7:])
+            if k == 'bridge-mcqv4src':
+               continue
+            if k == 'bridge-vlan-aware' and v == 'yes':
+                if self.ipcmd.bridge_is_vlan_aware(ifaceobj.name):
+                    ifaceobjcurr.update_config_with_status('bridge-vlan-aware',
+                               v, 0)
+                else:
+                    ifaceobjcurr.update_config_with_status('bridge-vlan-aware',
+                               v, 1)
+            elif k == 'bridge-stp':
+               # special case stp compare because it may
+               # contain more than one valid values
+               stp_on_vals = ['on', 'yes']
+               stp_off_vals = ['off']
+               if ((v in stp_on_vals and rv in stp_on_vals) or
+                   (v in stp_off_vals and rv in stp_off_vals)):
+                    ifaceobjcurr.update_config_with_status('bridge-stp',
+                               v, 0)
+               else:
+                    ifaceobjcurr.update_config_with_status('bridge-stp',
+                                v, 1)
+            elif k == 'bridge-ports':
+               # special case ports because it can contain regex or glob
+               running_port_list = rv.keys() if rv else []
+               bridge_port_list = self._get_bridge_port_list(ifaceobj)
+               if not running_port_list and not bridge_port_list:
+                  continue
+               portliststatus = 1
+               if running_port_list and bridge_port_list:
+                  difference = set(running_port_list
+                                 ).symmetric_difference(bridge_port_list)
+                  if not difference:
+                     portliststatus = 0
+                  ifaceobjcurr.update_config_with_status('bridge-ports',
+                              ' '.join(running_port_list)
+                              if running_port_list else '', portliststatus)
+            elif (k == 'bridge-pathcosts' or
+                  k == 'bridge-portprios' or k == 'bridge-portmcrouter'
+                  or k == 'bridge-portmcfl'):
+               brctlcmdattrname = k[11:].rstrip('s')
+               # for port attributes, the attributes are in a list
+               # <portname>=<portattrvalue>
+               status = 0
+               currstr = ''
+               vlist = self.parse_port_list(v)
+               if not vlist:
+                  continue
+               for vlistitem in vlist:
+                   try:
+                      (p, v) = vlistitem.split('=')
+                      currv = self.brctlcmd.get_bridgeport_attr(
+                                         ifaceobj.name, p,
+                                         brctlcmdattrname)
+                      if currv:
+                          currstr += ' %s=%s' %(p, currv)
+                      else:
+                          currstr += ' %s=%s' %(p, 'None')
+                      if currv != v:
+                          status = 1
+                   except Exception, e:
+                      self.log_warn(str(e))
+                   pass
+               ifaceobjcurr.update_config_with_status(k, currstr, status)
+            elif not rv:
+               ifaceobjcurr.update_config_with_status(k, 'notfound', 1)
+               continue
+            elif v != rv:
+               ifaceobjcurr.update_config_with_status(k, rv, 1)
+            else:
+               ifaceobjcurr.update_config_with_status(k, rv, 0)
+
+        self._query_check_bridge_vidinfo(ifaceobj, ifaceobjcurr)
+
+        self._query_check_mcqv4src(ifaceobj, ifaceobjcurr)
+
+    def _get_bridge_vids(self, bridgename, ifaceobj_getfunc):
+        ifaceobjs = ifaceobj_getfunc(bridgename)
+        for ifaceobj in ifaceobjs:
+            vids = ifaceobj.get_attr_value_first('bridge-vids')
+            if vids: return re.split(r'[\s\t,]\s*', vids)
+        return None
+
+    def _get_bridge_pvid(self, bridgename, ifaceobj_getfunc):
+        ifaceobjs = ifaceobj_getfunc(bridgename)
+        pvid = None
+        for ifaceobj in ifaceobjs:
+            pvid = ifaceobj.get_attr_value_first('bridge-pvid')
+        return pvid
+
+    def _get_bridge_name(self, ifaceobj):
+        return self.ipcmd.bridge_port_get_bridge_name(ifaceobj.name)
+
+    def _query_check_bridge_port_vidinfo(self, ifaceobj, ifaceobjcurr,
+                                         ifaceobj_getfunc, bridgename):
+        running_vidinfo = self._get_running_vidinfo()
+
+        attr_name = 'bridge-access'
+        vids = ifaceobj.get_attr_value_first(attr_name)
+        if vids:
+           running_pvids = running_vidinfo.get(ifaceobj.name,
+                                              {}).get('pvid')
+           running_vids = running_vidinfo.get(ifaceobj.name,
+                                              {}).get('vlan')
+           if (not running_pvids or running_pvids != vids or
+                   running_vids):
+               ifaceobjcurr.update_config_with_status(attr_name,
+                                running_pvids, 1)
+           else:
+               ifaceobjcurr.update_config_with_status(attr_name, vids, 0)
+           return
+
+        attr_name = 'bridge-vids'
+        vids = ifaceobj.get_attr_value_first(attr_name)
+        if vids:
+           vids = re.split(r'[\s\t]\s*', vids)
+           running_vids = running_vidinfo.get(ifaceobj.name,
+                                              {}).get('vlan')
+           if not running_vids or not self._compare_vids(vids, running_vids):
+               ifaceobjcurr.update_config_with_status(attr_name,
+                                ' '.join(running_vids), 1)
+           else:
+               ifaceobjcurr.update_config_with_status(attr_name,
+                                ' '.join(running_vids), 0)
+        else:
+           # check if it matches the bridge vids
+           bridge_vids = self._get_bridge_vids(bridgename, ifaceobj_getfunc)
+           running_vids = running_vidinfo.get(ifaceobj.name,
+                                              {}).get('vlan')
+           if (bridge_vids and (not running_vids  or
+                   not self._compare_vids(bridge_vids, running_vids))):
+              ifaceobjcurr.status = ifaceStatus.ERROR
+              ifaceobjcurr.status_str = 'bridge vid error'
+
+        running_pvid = running_vidinfo.get(ifaceobj.name,
+                                           {}).get('pvid')
+        attr_name = 'bridge-pvid'
+        pvid = ifaceobj.get_attr_value_first(attr_name)
+        if pvid:
+           if running_pvid and running_pvid == pvid:
+              ifaceobjcurr.update_config_with_status(attr_name,
+                                                     running_pvid, 0)
+           else:
+              ifaceobjcurr.update_config_with_status(attr_name,
+                                                     running_pvid, 1)
+        elif not running_pvid or running_pvid != '1':
+           ifaceobjcurr.status = ifaceStatus.ERROR
+           ifaceobjcurr.status_str = 'bridge pvid error'
+
+    def _query_check_bridge_port(self, ifaceobj, ifaceobjcurr,
+                                 ifaceobj_getfunc):
+        if not self._is_bridge_port(ifaceobj):
+            # Mark all bridge attributes as failed
+            ifaceobjcurr.check_n_update_config_with_status_many(ifaceobj,
+                    ['bridge-vids', 'bridge-pvid', 'bridge-access',
+                     'bridge-pathcosts', 'bridge-portprios',
+                     'bridge-portmcrouter',
+                     'bridge-portmcfl'], 1)
+            return
+        bridgename = self._get_bridge_name(ifaceobj)
+        if not bridgename:
+            self.logger.warn('%s: unable to determine bridge name'
+                             %ifaceobj.name)
+            return
+
+        if self.ipcmd.bridge_is_vlan_aware(bridgename):
+            self._query_check_bridge_port_vidinfo(ifaceobj, ifaceobjcurr,
+                                                  ifaceobj_getfunc,
+                                                  bridgename)
+        for attr, dstattr in {'bridge-pathcosts' : 'pathcost',
+                              'bridge-portprios' : 'priority',
+                              'bridge-portmcrouter' : 'mcrouter',
+                              'bridge-portmcfl' : 'mcfl' }.items():
+            attrval = ifaceobj.get_attr_value_first(attr)
+            if not attrval:
+                continue
+
+            try:
+                running_attrval = self.brctlcmd.get_bridgeport_attr(
+                                       bridgename, ifaceobj.name, dstattr)
+                if running_attrval != attrval:
+                    ifaceobjcurr.update_config_with_status(attr,
+                                            running_attrval, 1)
+                else:
+                    ifaceobjcurr.update_config_with_status(attr,
+                                            running_attrval, 0)
+            except Exception, e:
+                self.log_warn('%s: %s' %(ifaceobj.name, str(e)))
+
+    def _query_check(self, ifaceobj, ifaceobjcurr, ifaceobj_getfunc=None):
+        if self._is_bridge(ifaceobj):
+            self._query_check_bridge(ifaceobj, ifaceobjcurr)
+        else:
+            self._query_check_bridge_port(ifaceobj, ifaceobjcurr,
+                                          ifaceobj_getfunc)
+
+    def _query_running_bridge(self, ifaceobjrunning, ifaceobj_getfunc):
+        if self.ipcmd.bridge_is_vlan_aware(ifaceobjrunning.name):
+            ifaceobjrunning.update_config('bridge-vlan-aware', 'yes')
+            ifaceobjrunning.update_config_dict(self._query_running_attrs(
+                                               ifaceobjrunning,
+                                               ifaceobj_getfunc,
+                                               bridge_vlan_aware=True))
+        else: 
+            ifaceobjrunning.update_config_dict(self._query_running_attrs(
+                                               ifaceobjrunning, None))
+
+    def _query_running_bridge_port_attrs(self, ifaceobjrunning, bridgename):
+        if self.sysctl_get('net.bridge.bridge-stp-user-space') == '1':
+            return
+
+        v = self.brctlcmd.get_pathcost(bridgename, ifaceobjrunning.name)
+        if v and v != self.get_mod_subattr('bridge-pathcosts', 'default'):
+            ifaceobjrunning.update_config('bridge-pathcosts', v)
+
+        v = self.brctlcmd.get_pathcost(bridgename, ifaceobjrunning.name)
+        if v and v != self.get_mod_subattr('bridge-portprios', 'default'):
+            ifaceobjrunning.update_config('bridge-portprios', v)
+
+    def _query_running_bridge_port(self, ifaceobjrunning,
+                                   ifaceobj_getfunc=None):
+        bridgename = self.ipcmd.bridge_port_get_bridge_name(
+                                                ifaceobjrunning.name)
+        bridge_vids = None
+        bridge_pvid = None
+        if not bridgename:
+            self.logger.warn('%s: unable to find bridgename'
+                             %ifaceobjrunning.name)
+            return
+        if not self.ipcmd.bridge_is_vlan_aware(bridgename):
+            return
+
+        running_vidinfo = self._get_running_vidinfo()
+        bridge_port_vids = running_vidinfo.get(ifaceobjrunning.name,
+                                               {}).get('vlan')
+        bridge_port_pvid = running_vidinfo.get(ifaceobjrunning.name,
+                                               {}).get('pvid')
+
+        bridgeifaceobjlist = ifaceobj_getfunc(bridgename)
+        if bridgeifaceobjlist:
+           bridge_vids = bridgeifaceobjlist[0].get_attr_value('bridge-vids')
+           bridge_pvid = bridgeifaceobjlist[0].get_attr_value_first('bridge-pvid')
+
+        if not bridge_port_vids and bridge_port_pvid:
+            # must be an access port
+            if bridge_port_pvid != '1':
+               ifaceobjrunning.update_config('bridge-access',
+                                          bridge_port_pvid)
+        else:
+            if bridge_port_vids:
+                if (not bridge_vids or bridge_port_vids != bridge_vids):
+                   ifaceobjrunning.update_config('bridge-vids',
+                                        ' '.join(bridge_port_vids))
+            if bridge_port_pvid and bridge_port_pvid != '1':
+                if (not bridge_pvid or (bridge_port_pvid != bridge_pvid)):
+                    ifaceobjrunning.update_config('bridge-pvid',
+                                        bridge_port_pvid)
+        self._query_running_bridge_port_attrs(ifaceobjrunning, bridgename)
+
+    def _query_running(self, ifaceobjrunning, ifaceobj_getfunc=None):
+        if self.brctlcmd.bridge_exists(ifaceobjrunning.name):
+            self._query_running_bridge(ifaceobjrunning, ifaceobj_getfunc)
+        elif self.brctlcmd.is_bridge_port(ifaceobjrunning.name):
+            self._query_running_bridge_port(ifaceobjrunning, ifaceobj_getfunc)
+
+    _run_ops = {'pre-up' : _up,
+               'post-down' : _down,
+               'query-checkcurr' : _query_check,
+               'query-running' : _query_running}
+
+    def get_ops(self):
+        """ returns list of ops supported by this module """
+        return self._run_ops.keys()
+
+    def _init_command_handlers(self):
+        flags = self.get_flags()
+        if not self.ipcmd:
+            self.ipcmd = iproute2(**flags)
+        if not self.brctlcmd:
+            self.brctlcmd = brctl(**flags)
+
+    def run(self, ifaceobj, operation, query_ifaceobj=None,
+            ifaceobj_getfunc=None):
+        """ run bridge configuration on the interface object passed as
+            argument. Can create bridge interfaces if they dont exist already
+
+        Args:
+            **ifaceobj** (object): iface object
+
+            **operation** (str): any of 'pre-up', 'post-down', 'query-checkcurr',
+                                 'query-running'
+
+        Kwargs:
+            **query_ifaceobj** (object): query check ifaceobject. This is only
+                valid when op is 'query-checkcurr'. It is an object same as
+                ifaceobj, but contains running attribute values and its config
+                status. The modules can use it to return queried running state
+                of interfaces. status is success if the running state is same
+                as user required state in ifaceobj. error otherwise.
+        """
+        op_handler = self._run_ops.get(operation)
+        if not op_handler:
+           return
+        self._init_command_handlers()
+        self._flush_running_vidinfo()
+        if operation == 'query-checkcurr':
+            op_handler(self, ifaceobj, query_ifaceobj,
+                       ifaceobj_getfunc=ifaceobj_getfunc)
+        else:
+            op_handler(self, ifaceobj, ifaceobj_getfunc=ifaceobj_getfunc)
diff --git a/addons/bridgevlan.py b/addons/bridgevlan.py
new file mode 100644 (file)
index 0000000..44824c7
--- /dev/null
@@ -0,0 +1,170 @@
+#!/usr/bin/python
+#
+# Copyright 2014 Cumulus Networks, Inc. All rights reserved.
+# Author: Roopa Prabhu, roopa@cumulusnetworks.com
+#
+
+from ifupdown.iface import *
+from ifupdownaddons.modulebase import moduleBase
+from ifupdownaddons.iproute2 import iproute2
+from ifupdownaddons.bridgeutils import brctl
+import logging
+
+class bridgevlan(moduleBase):
+    """  ifupdown2 addon module to configure vlan attributes on a vlan
+         aware bridge """
+
+    _modinfo = {'mhelp' : 'bridgevlan module configures vlan attributes ' +
+                        'on a vlan aware bridge. This module only ' +
+                        'understands vlan interface name ' +
+                        'with dot notations. eg br0.100. where br0 is the ' +
+                        'vlan aware bridge this config is for',
+                'attrs' : {
+                        'bridge-igmp-querier-src' :
+                            { 'help' : 'bridge igmp querier src. Must be ' +
+                                   'specified under the vlan interface',
+                              'example' : ['bridge-igmp-querier-src 172.16.101.1']}}}
+
+    def __init__(self, *args, **kargs):
+        moduleBase.__init__(self, *args, **kargs)
+        self.brctlcmd = None
+        self.ipcmd = None
+
+    def _is_bridge_vlan_device(self, ifaceobj):
+        if ifaceobj.type == ifaceType.BRIDGE_VLAN:
+            return True
+        return False
+
+    def _get_bridge_n_vlan(self, ifaceobj):
+        vlist = ifaceobj.name.split('.', 1)
+        if len(vlist) == 2:
+            return (vlist[0], vlist[1])
+        return None
+
+    def _get_bridgename(self, ifaceobj):
+        vlist = ifaceobj.name.split('.', 1)
+        if len(vlist) == 2:
+            return vlist[0]
+        return None
+
+    def get_dependent_ifacenames(self, ifaceobj, ifaceobjs_all=None):
+        if not self._is_bridge_vlan_device(ifaceobj):
+            return None
+        return [self._get_bridgename(ifaceobj)]
+
+    def _up(self, ifaceobj):
+        try:
+            (bridgename, vlan) = self._get_bridge_n_vlan(ifaceobj)
+            vlanid = int(vlan, 10)
+        except:
+            self.logger.warn('%s: bridge vlan interface name ' %ifaceobj.name +
+                    'does not correspond to format (eg. br0.100)')
+            raise
+
+        if not self.ipcmd.link_exists(bridgename):
+            #self.logger.warn('%s: bridge %s does not exist' %(ifaceobj.name,
+            #                 bridgename))
+            return
+
+        running_mcqv4src = {}
+        if not self.PERFMODE:
+            running_mcqv4src = self.brctlcmd.get_mcqv4src(bridgename)
+        if running_mcqv4src:
+            r_mcqv4src = running_mcqv4src.get(vlan)
+        else:
+            r_mcqv4src = None
+        mcqv4src = ifaceobj.get_attr_value_first('bridge-igmp-querier-src')
+        if not mcqv4src:
+            if r_mcqv4src:
+                self.brctlcmd.del_mcqv4src(bridgename, vlanid)
+            return
+
+        if r_mcqv4src and r_mcqv4src != mcqv4src:
+            self.brctlcmd.del_mcqv4src(bridgename, vlanid)
+            self.brctlcmd.set_mcqv4src(bridgename, vlanid, mcqv4src)
+        else:
+            self.brctlcmd.set_mcqv4src(bridgename, vlanid, mcqv4src)
+
+    def _down(self, ifaceobj):
+        try:
+            (bridgename, vlan) = self._get_bridge_n_vlan(ifaceobj)
+            vlanid = int(vlan, 10)
+        except:
+            self.logger.warn('%s: bridge vlan interface name ' %ifaceobj.name +
+                    'does not correspond to format (eg. br0.100)')
+            raise
+
+        if not self.ipcmd.link_exists(bridgename):
+            #self.logger.warn('%s: bridge %s does not exist' %(ifaceobj.name,
+            #                 bridgename))
+            return
+        mcqv4src = ifaceobj.get_attr_value_first('bridge-igmp-querier-src')
+        if mcqv4src:
+           self.brctlcmd.del_mcqv4src(bridgename, vlanid)
+
+    def _query_running_bridge_igmp_querier_src(self, ifaceobj):
+        (bridgename, vlanid) = ifaceobj.name.split('.')
+        running_mcqv4src = self.brctlcmd.get_mcqv4src(bridgename)
+        if running_mcqv4src:
+           return running_mcqv4src.get(vlanid)
+        return None
+
+    def _query_check(self, ifaceobj, ifaceobjcurr):
+        attrval = ifaceobj.get_attr_value_first('bridge-igmp-querier-src')
+        if attrval:
+            running_mcq = self._query_running_bridge_igmp_querier_src(ifaceobj)
+            if not running_mcq or running_mcq != attrval:
+                ifaceobjcurr.update_config_with_status(
+                        'bridge-igmp-querier-src', running_mcq, 1)
+            else:
+                ifaceobjcurr.update_config_with_status(
+                        'bridge-igmp-querier-src', attrval, 0)
+                ifaceobjcurr.status = ifaceStatus.SUCCESS
+        return
+
+    def _query_running(self, ifaceobjrunning):
+        # XXX not supported
+        return
+
+    _run_ops = {'pre-up' : _up,
+               'post-down' : _down,
+               'query-checkcurr' : _query_check,
+               'query-running' : _query_running}
+
+    def get_ops(self):
+        """ returns list of ops supported by this module """
+        return self._run_ops.keys()
+
+    def _init_command_handlers(self):
+        if not self.ipcmd:
+            self.ipcmd = iproute2(**self.get_flags())
+        if not self.brctlcmd:
+            self.brctlcmd = brctl(**self.get_flags())
+
+    def run(self, ifaceobj, operation, query_ifaceobj=None, **extra_args):
+        """ run vlan configuration on the interface object passed as argument
+
+        Args:
+            **ifaceobj** (object): iface object
+
+            **operation** (str): any of 'pre-up', 'post-down', 'query-checkcurr',
+                                 'query-running'
+        Kwargs:
+            **query_ifaceobj** (object): query check ifaceobject. This is only
+                valid when op is 'query-checkcurr'. It is an object same as
+                ifaceobj, but contains running attribute values and its config
+                status. The modules can use it to return queried running state
+                of interfaces. status is success if the running state is same
+                as user required state in ifaceobj. error otherwise.
+        """
+        op_handler = self._run_ops.get(operation)
+        if not op_handler:
+            return
+        if (operation != 'query-running' and
+                not self._is_bridge_vlan_device(ifaceobj)):
+            return
+        self._init_command_handlers()
+        if operation == 'query-checkcurr':
+            op_handler(self, ifaceobj, query_ifaceobj)
+        else:
+            op_handler(self, ifaceobj)
diff --git a/addons/dhcp.py b/addons/dhcp.py
new file mode 100644 (file)
index 0000000..ed68466
--- /dev/null
@@ -0,0 +1,129 @@
+#!/usr/bin/python
+#
+# Copyright 2014 Cumulus Networks, Inc. All rights reserved.
+# Author: Roopa Prabhu, roopa@cumulusnetworks.com
+#
+
+try:
+    from ipaddr import IPNetwork
+    from sets import Set
+    from ifupdown.iface import *
+    from ifupdownaddons.modulebase import moduleBase
+    from ifupdownaddons.dhclient import dhclient
+    from ifupdownaddons.iproute2 import iproute2
+except ImportError, e:
+    raise ImportError (str(e) + "- required module not found")
+
+class dhcp(moduleBase):
+    """ ifupdown2 addon module to configure dhcp on interface """
+
+    def __init__(self, *args, **kargs):
+        moduleBase.__init__(self, *args, **kargs)
+        self.dhclientcmd = dhclient(**kargs)
+        self.ipcmd = None
+
+    def _up(self, ifaceobj):
+        try:
+            if ifaceobj.addr_family == 'inet':
+                # First release any existing dhclient processes
+                try:
+                    if not self.PERFMODE:
+                        self.dhclientcmd.stop(ifaceobj.name)
+                except:
+                    pass
+                self.dhclientcmd.start(ifaceobj.name)
+            elif ifaceobj.addr_family == 'inet6':
+                accept_ra = ifaceobj.get_attr_value_first('accept_ra')
+                if accept_ra:
+                    # XXX: Validate value
+                    self.sysctl_set('net.ipv6.conf.%s' %ifaceobj.name +
+                            '.accept_ra', accept_ra)
+                autoconf = ifaceobj.get_attr_value_first('autoconf')
+                if autoconf:
+                    # XXX: Validate value
+                    self.sysctl_set('net.ipv6.conf.%s' %ifaceobj.name +
+                            '.autoconf', autoconf)
+                    try:
+                        self.dhclientcmd.stop6(ifaceobj.name)
+                    except:
+                        pass
+                self.dhclientcmd.start6(ifaceobj.name)
+        except Exception, e:
+            self.log_error(str(e))
+
+    def _down(self, ifaceobj):
+        self.dhclientcmd.release(ifaceobj.name)
+        self.ipcmd.link_down(ifaceobj.name)
+
+    def _query_check(self, ifaceobj, ifaceobjcurr):
+        if self.dhclientcmd.is_running(ifaceobjcurr.name):
+            ifaceobjcurr.addr_family = 'inet'
+            if ifaceobj.addr_family != 'inet':
+                ifaceobjcurr.status = ifaceStatus.ERROR
+            ifaceobjcurr.addr_method = 'dhcp'
+            ifaceobjcurr.status = ifaceStatus.SUCCESS
+        elif self.dhclientcmd.is_running6(ifaceobjcurr.name):
+            ifaceobjcurr.addr_family = 'inet6'
+            if ifaceobj.addr_family != 'inet6':
+                ifaceobjcurr.status = ifaceStatus.ERROR
+            ifaceobjcurr.addr_method = 'dhcp'
+            ifaceobjcurr.status = ifaceStatus.SUCCESS
+        else:
+            ifaceobjcurr.addr_family = None
+            ifaceobjcurr.status = ifaceStatus.ERROR
+
+    def _query_running(self, ifaceobjrunning):
+        if not self.ipcmd.link_exists(ifaceobjrunning.name):
+            return
+        if self.dhclientcmd.is_running(ifaceobjrunning.name):
+            ifaceobjrunning.addr_family = 'inet'
+            ifaceobjrunning.addr_method = 'dhcp'
+        elif self.dhclientcmd.is_running6(ifaceobjrunning.name):
+            ifaceobjrunning.addr_family = 'inet6'
+            ifaceobjrunning.addr_method = 'dhcp6'
+
+    _run_ops = {'up' : _up,
+               'down' : _down,
+               'query-checkcurr' : _query_check,
+               'query-running' : _query_running }
+
+    def get_ops(self):
+        """ returns list of ops supported by this module """
+        return self._run_ops.keys()
+
+    def _init_command_handlers(self):
+        if not self.ipcmd:
+            self.ipcmd = iproute2(**self.get_flags())
+
+    def run(self, ifaceobj, operation, query_ifaceobj=None, **extra_args):
+        """ run dhcp configuration on the interface object passed as argument
+
+        Args:
+            **ifaceobj** (object): iface object
+
+            **operation** (str): any of 'up', 'down', 'query-checkcurr',
+                                 'query-running'
+
+        Kwargs:
+            **query_ifaceobj** (object): query check ifaceobject. This is only
+                valid when op is 'query-checkcurr'. It is an object same as
+                ifaceobj, but contains running attribute values and its config
+                status. The modules can use it to return queried running state
+                of interfaces. status is success if the running state is same
+                as user required state in ifaceobj. error otherwise.
+        """
+        op_handler = self._run_ops.get(operation)
+        if not op_handler:
+            return
+        try:
+            if (operation != 'query-running' and
+                   (ifaceobj.addr_method != 'dhcp' and 
+                       ifaceobj.addr_method != 'dhcp6')):
+                return
+        except:
+            return
+        self._init_command_handlers()
+        if operation == 'query-checkcurr':
+            op_handler(self, ifaceobj, query_ifaceobj)
+        else:
+            op_handler(self, ifaceobj)
diff --git a/addons/ethtool.py b/addons/ethtool.py
new file mode 100644 (file)
index 0000000..f578128
--- /dev/null
@@ -0,0 +1,240 @@
+#!/usr/bin/python
+#
+# Copyright 2014 Cumulus Networks, Inc. All rights reserved.
+# Author: Roopa Prabhu, roopa@cumulusnetworks.com
+#
+import json
+import ifupdown.policymanager as policymanager
+
+try:
+    from ipaddr import IPNetwork
+    from sets import Set
+    from ifupdown.iface import *
+    from ifupdownaddons.utilsbase import *
+    from ifupdownaddons.modulebase import moduleBase
+    from ifupdownaddons.iproute2 import iproute2
+except ImportError, e:
+    raise ImportError (str(e) + "- required module not found")
+
+class ethtool(moduleBase,utilsBase):
+    """  ifupdown2 addon module to configure ethtool attributes """
+
+    _modinfo = {'mhelp' : 'ethtool configuration module for interfaces',
+                'attrs': {
+                      'link-speed' :
+                            {'help' : 'set link speed',
+                             'example' : ['link-speed 1000'],
+                             'default' : 'varies by platform and port'},
+                      'link-duplex' :
+                            {'help': 'set link duplex',
+                             'example' : ['link-duplex full'],
+                             'validvals' : ['half', 'full'],
+                             'default' : 'full'},
+                      'link-autoneg' :
+                            {'help': 'set autonegotiation',
+                             'example' : ['link-autoneg on'],
+                             'validvals' : ['on', 'off'],
+                             'default' : 'varies by platform and port'}}}
+
+    def __init__(self, *args, **kargs):
+        moduleBase.__init__(self, *args, **kargs)
+        self.ipcmd = None
+
+    def _post_up(self, ifaceobj, operation='post_up'):
+        """
+        _post_up and _pre_down will reset the layer 2 attributes to default policy
+        settings.
+        """
+        if not self.ipcmd.link_exists(ifaceobj.name):
+            return
+        cmd = ''
+        for attr in ['speed', 'duplex', 'autoneg']:
+            # attribute existed before but we must reset to default
+            config_val = ifaceobj.get_attr_value_first('link-%s'%attr)
+            default_val = policymanager.policymanager_api.get_iface_default(
+                module_name='ethtool',
+                ifname=ifaceobj.name,
+                attr='link-%s'%attr)
+
+            # check running values
+            running_val = None
+            if attr == 'autoneg':
+                # we can only get autoneg from ethtool
+                output = self.exec_commandl(['ethtool', ifaceobj.name])
+                running_val = self.get_autoneg(ethtool_output=output)
+            else:
+                running_val = self.read_file_oneline('/sys/class/net/%s/%s' % \
+                                                     (ifaceobj.name, attr))
+            if config_val and config_val == running_val:
+                # running value is what is configured, do nothing
+                continue
+            if not config_val and default_val and default_val == running_val:
+                # nothing configured but the default is running
+                continue
+            # if we got this far, we need to change it
+            if config_val and (config_val != running_val):
+                # if the configured value is not set, set it
+                cmd += ' %s %s' % (attr, config_val)
+            elif default_val and (default_val != running_val):
+                # or if it has a default not equal to running value, set it
+                cmd += ' %s %s' % (attr, default_val)
+            else:
+                # no value set nor default, leave it alone
+                pass
+        if cmd:
+            self.logger.debug('ethtool %s: iface %s cmd is %s' % \
+                              (operation, ifaceobj.name, cmd))
+            try:
+                # we should only be calling ethtool if there
+                # is a speed set or we can find a default speed
+                # because we should only be calling ethtool on swp ports
+                cmd = 'ethtool -s %s %s' %(ifaceobj.name, cmd)
+                self.exec_command(cmd)
+            except Exception, e:
+                ifaceobj.status = ifaceStatus.ERROR
+                self.log_warn('%s: %s' %(ifaceobj.name, str(e)))
+        else:
+            pass
+
+    def _pre_down(self, ifaceobj):
+        pass #self._post_up(ifaceobj,operation="_pre_down")
+
+    def _query_check(self, ifaceobj, ifaceobjcurr):
+        """
+        _query_check() needs to compare the configured (or running)
+        attribute with the running attribute.
+
+        If there is nothing configured, we compare the default attribute with
+        the running attribute and FAIL if they are different.
+        This is because a reboot will lose their running attribute
+        (the default will get set).
+        """
+        for attr in ['speed', 'duplex', 'autoneg']:
+            # autoneg comes from ethtool whereas speed and duplex from /sys/class
+            if attr == 'autoneg':
+                output = self.exec_commandl(['ethtool', ifaceobj.name])
+                running_attr = self.get_autoneg(ethtool_output=output)
+            else:
+                running_attr = self.read_file_oneline('/sys/class/net/%s/%s' % \
+                                                      (ifaceobj.name, attr))
+
+            configured = ifaceobj.get_attr_value_first('link-%s'%attr)
+            default = policymanager.policymanager_api.get_iface_default(
+                module_name='ethtool',
+                ifname=ifaceobj.name,
+                attr='link-%s'%attr)
+
+            # there is a case where there is no running config or
+            # (there is no default and it is not configured).
+            # In this case, we do nothing (e.g. eth0 has only a
+            # default duplex, lo has nothing)
+            if (not running_attr or (not configured and not default)):
+                continue
+
+            # we make sure we can get a running value first
+            if (running_attr and configured and running_attr == configured):
+                # PASS since running is what is configured 
+                ifaceobjcurr.update_config_with_status('link-%s'%attr,
+                                                       running_attr, 0)
+            elif (running_attr and configured and running_attr != configured):
+                # We show a FAIL since it is not the configured or default
+                ifaceobjcurr.update_config_with_status('link-%s'%attr,
+                                                       running_attr, 1)
+            elif (running_attr and default and running_attr == default):
+                # PASS since running is default
+                ifaceobjcurr.update_config_with_status('link-%s'%attr,
+                                                       running_attr, 0)
+            elif (default or configured):
+                # We show a FAIL since it is not the configured or default
+                ifaceobjcurr.update_config_with_status('link-%s'%attr,
+                                                       running_attr, 1)
+        return
+
+    def get_autoneg(self,ethtool_output=None):
+        """
+        get_autoneg simply calls the ethtool command and parses out
+        the autoneg value.
+        """
+        ethtool_attrs = ethtool_output.split()
+        if ('Auto-negotiation:' in ethtool_attrs):
+            return(ethtool_attrs[ethtool_attrs.index('Auto-negotiation:')+1])
+        else:
+            return(None)
+
+    def _query_running(self, ifaceobj, ifaceobj_getfunc=None):
+        """
+        _query_running looks at the speed and duplex from /sys/class
+        and retreives autoneg from ethtool.  We do not report autoneg
+        if speed is not available because this usually means the link is
+        down and the autoneg value is not reliable when the link is down.
+        """
+        # do not bother showing swp ifaces that are not up for the speed
+        # duplex and autoneg are not reliable.
+        if not self.ipcmd.is_link_up(ifaceobj.name):
+            return
+        for attr in ['speed', 'duplex', 'autoneg']:
+            # autoneg comes from ethtool whereas speed and duplex from /sys/class
+            running_attr = None
+            try:
+                if attr == 'autoneg':
+                    output=self.exec_commandl(['ethtool', ifaceobj.name])
+                    running_attr = self.get_autoneg(ethtool_output=output)
+                else:
+                    running_attr = self.read_file_oneline('/sys/class/net/%s/%s' % \
+                                                          (ifaceobj.name, attr))
+            except:
+                # for nonexistent interfaces, we get an error (rc = 256 or 19200)
+                pass
+
+            # show it
+            if (running_attr):
+                ifaceobj.update_config('link-%s'%attr, running_attr)
+
+        return
+
+    _run_ops = {'pre-down' : _pre_down,
+                'post-up' : _post_up,
+                'query-checkcurr' : _query_check,
+                'query-running' : _query_running }
+
+    def get_ops(self):
+        """ returns list of ops supported by this module """
+        return self._run_ops.keys()
+
+    def _init_command_handlers(self):
+        if not self.ipcmd:
+            self.ipcmd = iproute2(**self.get_flags())
+
+    def run(self, ifaceobj, operation, query_ifaceobj=None, **extra_args):
+        """ run ethtool configuration on the interface object passed as
+            argument
+
+        Args:
+            **ifaceobj** (object): iface object
+
+            **operation** (str): any of 'post-up', 'query-checkcurr',
+                'query-running'
+        Kwargs:
+            **query_ifaceobj** (object): query check ifaceobject. This is only
+                valid when op is 'query-checkcurr'. It is an object same as
+                ifaceobj, but contains running attribute values and its config
+                status. The modules can use it to return queried running state
+                of interfaces. status is success if the running state is same
+                as user required state in ifaceobj. error otherwise.
+        """
+        op_handler = self._run_ops.get(operation)
+        if not op_handler:
+            return
+        self._init_command_handlers()
+
+        # check to make sure we are only checking/setting interfaces with
+        # no lower interfaces.   No bridges, no vlans, loopbacks.
+        if ifaceobj.lowerifaces != None or \
+           self.ipcmd.link_isloopback(ifaceobj.name) or \
+           self.ipcmd.is_vlan_device_by_name(ifaceobj.name):
+            return
+
+        if operation == 'query-checkcurr':
+            op_handler(self, ifaceobj, query_ifaceobj)
+        else:
+            op_handler(self, ifaceobj)
diff --git a/addons/ifenslave.py b/addons/ifenslave.py
new file mode 100644 (file)
index 0000000..ba37732
--- /dev/null
@@ -0,0 +1,442 @@
+#!/usr/bin/python
+#
+# Copyright 2014 Cumulus Networks, Inc. All rights reserved.
+# Author: Roopa Prabhu, roopa@cumulusnetworks.com
+#
+
+from sets import Set
+from ifupdown.iface import *
+import ifupdownaddons
+from ifupdownaddons.modulebase import moduleBase
+from ifupdownaddons.ifenslaveutil import ifenslaveutil
+from ifupdownaddons.iproute2 import iproute2
+import ifupdown.rtnetlink_api as rtnetlink_api
+
+class ifenslave(moduleBase):
+    """  ifupdown2 addon module to configure bond interfaces """
+    _modinfo = { 'mhelp' : 'bond configuration module',
+                    'attrs' : {
+                    'bond-use-carrier':
+                         {'help' : 'bond use carrier',
+                          'validvals' : ['0', '1'],
+                          'default' : '1',
+                          'example': ['bond-use-carrier 1']},
+                     'bond-num-grat-arp':
+                         {'help' : 'bond use carrier',
+                          'validrange' : ['0', '255'],
+                          'default' : '1',
+                          'example' : ['bond-num-grat-arp 1']},
+                     'bond-num-unsol-na' :
+                         {'help' : 'bond slave devices',
+                          'validrange' : ['0', '255'],
+                          'default' : '1',
+                          'example' : ['bond-num-unsol-na 1']},
+                     'bond-xmit-hash-policy' :
+                         {'help' : 'bond slave devices',
+                          'validvals' : ['layer2', 'layer3+4', 'layer2+3'],
+                          'default' : 'layer2',
+                          'example' : ['bond-xmit-hash-policy layer2']},
+                     'bond-miimon' :
+                         {'help' : 'bond miimon',
+                          'validrange' : ['0', '255'],
+                          'default' : '0',
+                          'example' : ['bond-miimon 0']},
+                     'bond-mode' :
+                         {'help' : 'bond mode',
+                          'validvals' : ['balance-rr', 'active-backup',
+                                          'balance-xor', 'broadcast', '802.3ad',
+                                          'balance-tlb', 'balance-alb'],
+                          'default' : 'balance-rr',
+                          'example' : ['bond-mode 802.3ad']},
+                     'bond-lacp-rate':
+                         {'help' : 'bond lacp rate',
+                          'validvals' : ['0', '1'],
+                          'default' : '0',
+                          'example' : ['bond-lacp-rate 0']},
+                     'bond-min-links':
+                         {'help' : 'bond min links',
+                          'default' : '0',
+                          'example' : ['bond-min-links 0']},
+                     'bond-ad-sys-priority':
+                         {'help' : '802.3ad system priority',
+                          'default' : '65535',
+                          'example' : ['bond-ad-sys-priority 65535']},
+                     'bond-ad-sys-mac-addr':
+                         {'help' : '802.3ad system mac address',
+                          'default' : '00:00:00:00:00:00',
+                         'example' : ['bond-ad-sys-mac-addr 00:00:00:00:00:00']},
+                     'bond-lacp-fallback-allow':
+                         {'help' : 'allow lacp fall back',
+                          'compat' : True,
+                          'validvals' : ['0', '1'],
+                          'default' : '0',
+                          'example' : ['bond-lacp-fallback-allow 0']},
+                     'bond-lacp-fallback-period':
+                         {'help' : 'grace period (seconds) for lacp fall back',
+                          'compat' : True,
+                          'validrange' : ['0', '100'],
+                          'default' : '90',
+                          'example' : ['bond-lacp-fallback-period 100']},
+                     'bond-lacp-fallback-priority':
+                         {'help' : 'slave priority for lacp fall back',
+                          'compat' : True,
+                          'example' : ['bond-lacp-fallback-priority swp1=1 swp2=1 swp3=2']},
+                     'bond-lacp-bypass-allow':
+                         {'help' : 'allow lacp bypass',
+                          'validvals' : ['0', '1'],
+                          'default' : '0',
+                          'example' : ['bond-lacp-bypass-allow 0']},
+                     'bond-lacp-bypass-period':
+                         {'help' : 'grace period (seconds) for lacp bypass',
+                          'validrange' : ['0', '900'],
+                          'default' : '0',
+                          'example' : ['bond-lacp-bypass-period 100']},
+                     'bond-lacp-bypass-priority':
+                         {'help' : 'slave priority for lacp bypass',
+                          'example' : ['bond-lacp-bypass-priority swp1=1 swp2=1 swp3=2']},
+                     'bond-slaves' :
+                        {'help' : 'bond slaves',
+                         'required' : True,
+                         'example' : ['bond-slaves swp1 swp2',
+                                      'bond-slaves glob swp1-2',
+                                      'bond-slaves regex (swp[1|2)']}}}
+
+    def __init__(self, *args, **kargs):
+        ifupdownaddons.modulebase.moduleBase.__init__(self, *args, **kargs)
+        self.ipcmd = None
+        self.ifenslavecmd = None
+
+    def _is_bond(self, ifaceobj):
+        if ifaceobj.get_attr_value_first('bond-slaves'):
+            return True
+        return False
+
+    def get_dependent_ifacenames(self, ifaceobj, ifacenames_all=None):
+        """ Returns list of interfaces dependent on ifaceobj """
+
+        if not self._is_bond(ifaceobj):
+            return None
+        slave_list = self.parse_port_list(ifaceobj.get_attr_value_first(
+                                    'bond-slaves'), ifacenames_all)
+        ifaceobj.dependency_type = ifaceDependencyType.MASTER_SLAVE
+        # Also save a copy for future use
+        ifaceobj.priv_data = list(slave_list)
+        if ifaceobj.link_type != ifaceLinkType.LINK_NA:
+           ifaceobj.link_type = ifaceLinkType.LINK_MASTER
+        ifaceobj.link_kind |= ifaceLinkKind.BOND
+        ifaceobj.role |= ifaceRole.MASTER
+
+        return slave_list
+
+    def get_dependent_ifacenames_running(self, ifaceobj):
+        self._init_command_handlers()
+        return self.ifenslavecmd.get_slaves(ifaceobj.name)
+
+    def _get_slave_list(self, ifaceobj):
+        """ Returns slave list present in ifaceobj config """
+
+        # If priv data already has slave list use that first.
+        if ifaceobj.priv_data:
+            return ifaceobj.priv_data
+        slaves = ifaceobj.get_attr_value_first('bond-slaves')
+        if slaves:
+            return self.parse_port_list(slaves)
+        else:
+            return None
+
+    def fetch_attr(self, ifaceobj, attrname):
+        attrval = ifaceobj.get_attr_value_first(attrname)
+        if attrval:
+            msg = ('%s: invalid value %s for attr %s.'
+                    %(ifaceobj.name, attrval, attrname))
+            optiondict = self.get_mod_attr(attrname)
+            if not optiondict:
+                return None
+            validvals = optiondict.get('validvals')
+            if validvals and attrval not in validvals:
+                raise Exception(msg + ' Valid values are %s' %str(validvals))
+            validrange = optiondict.get('validrange')
+            if validrange:
+                if (int(attrval) < int(validrange[0]) or
+                        int(attrval) > int(validrange[1])):
+                    raise Exception(msg + ' Valid range is [%s,%s]'
+                                    %(validrange[0], validrange[1]))
+            if attrname == 'bond-mode' and attrval == '802.3ad':
+               dattrname = 'bond-min-links'
+               min_links = ifaceobj.get_attr_value_first(dattrname)
+               if not min_links or min_links == '0':
+                   self.logger.warn('%s: required attribute %s'
+                        %(ifaceobj.name, dattrname) +
+                        ' not present or set to \'0\'')
+        elif attrname in ['bond-lacp-bypass-allow']:
+            # For some attrs, set default values
+            optiondict = self.get_mod_attr(attrname)
+            if optiondict:
+                return optiondict.get('default')
+        return attrval
+
+    def _apply_master_settings(self, ifaceobj):
+        have_attrs_to_set = 0
+        linkup = False
+        ifenslavecmd_attrmap =  OrderedDict([('bond-mode' , 'mode'),
+                                 ('bond-miimon' , 'miimon'),
+                                 ('bond-use-carrier', 'use_carrier'),
+                                 ('bond-lacp-rate' , 'lacp_rate'),
+                                 ('bond-xmit-hash-policy' , 'xmit_hash_policy'),
+                                 ('bond-min-links' , 'min_links'),
+                                 ('bond-num-grat-arp' , 'num_grat_arp'),
+                                 ('bond-num-unsol-na' , 'num_unsol_na'),
+                                 ('bond-ad-sys-mac-addr' , 'ad_sys_mac_addr'),
+                                 ('bond-ad-sys-priority' , 'ad_sys_priority'),
+                                 ('bond-lacp-fallback-allow', 'lacp_bypass_allow'),
+                                 ('bond-lacp-fallback-period', 'lacp_bypass_period'),
+                                 ('bond-lacp-bypass-allow', 'lacp_bypass_allow'),
+                                 ('bond-lacp-bypass-period', 'lacp_bypass_period')])
+        linkup = self.ipcmd.is_link_up(ifaceobj.name)
+        try:
+            # order of attributes set matters for bond, so
+            # construct the list sequentially
+            attrstoset = OrderedDict()
+            for k, dstk in ifenslavecmd_attrmap.items():
+                v = self.fetch_attr(ifaceobj, k)
+                if v:
+                    attrstoset[dstk] = v
+            if not attrstoset:
+                return
+            have_attrs_to_set = 1
+            self.ifenslavecmd.set_attrs(ifaceobj.name, attrstoset,
+                    self.ipcmd.link_down if linkup else None)
+        except:
+            raise
+        finally:
+            if have_attrs_to_set and linkup:
+                self.ipcmd.link_up(ifaceobj.name)
+
+    def _add_slaves(self, ifaceobj):
+        runningslaves = []
+
+        slaves = self._get_slave_list(ifaceobj)
+        if not slaves:
+            self.logger.debug('%s: no slaves found' %ifaceobj.name)
+            return
+
+        if not self.PERFMODE:
+            runningslaves = self.ifenslavecmd.get_slaves(ifaceobj.name);
+
+        for slave in Set(slaves).difference(Set(runningslaves)):
+            if not self.PERFMODE and not self.ipcmd.link_exists(slave):
+                    self.log_warn('%s: skipping slave %s, does not exist'
+                                  %(ifaceobj.name, slave))
+                    continue
+            link_up = False
+            if self.ipcmd.is_link_up(slave):
+               rtnetlink_api.rtnl_api.link_set(slave, "down")
+               link_up = True
+            self.ipcmd.link_set(slave, 'master', ifaceobj.name)
+            if link_up or ifaceobj.link_type != ifaceLinkType.LINK_NA:
+               try:
+                    rtnetlink_api.rtnl_api.link_set(slave, "up")
+               except Exception, e:
+                    self.logger.debug('%s: %s: link set up (%s)'
+                                      %(ifaceobj.name, slave, str(e)))
+                    pass
+
+        if runningslaves:
+            # Delete active slaves not in the new slave list
+            [ self.ifenslavecmd.remove_slave(ifaceobj.name, s)
+                    for s in runningslaves if s not in slaves ]
+
+    def _set_clag_enable(self, ifaceobj):
+        attrval = ifaceobj.get_attr_value_first('clag-id')
+        attrval = attrval if attrval else '0'
+        self.ifenslavecmd.set_clag_enable(ifaceobj.name, attrval)
+
+    def _apply_slaves_lacp_bypass_prio(self, ifaceobj):
+        slaves = self.ifenslavecmd.get_slaves(ifaceobj.name)
+        if not slaves:
+           return
+        attrval = ifaceobj.get_attrs_value_first(['bond-lacp-bypass-priority',
+                                'bond-lacp-fallback-priority'])
+        if attrval:
+            portlist = self.parse_port_list(attrval)
+            if not portlist:
+                self.log_warn('%s: could not parse \'%s %s\''
+                              %(ifaceobj.name, attrname, attrval))
+                return
+            for p in portlist:
+                try:
+                    (port, val) = p.split('=')
+                    if port not in slaves:
+                        self.log_warn('%s: skipping slave %s, does not exist' 
+                                      %(ifaceobj.name, port))
+                        continue
+                    slaves.remove(port)
+                    self.ifenslavecmd.set_lacp_fallback_priority(
+                                            ifaceobj.name, port, val)
+                except Exception, e:
+                    self.log_warn('%s: failed to set lacp_fallback_priority %s (%s)'
+                                  %(ifaceobj.name, port, str(e)))
+
+        for p in slaves:
+            try:
+                self.ifenslavecmd.set_lacp_fallback_priority(ifaceobj.name, p, '0')
+            except Exception, e:
+                self.log_warn('%s: failed to clear lacp_bypass_priority %s (%s)'
+                              %(ifaceobj.name, p, str(e)))
+
+
+    def _up(self, ifaceobj):
+        try:
+            if not self.ipcmd.link_exists(ifaceobj.name):
+                self.ifenslavecmd.create_bond(ifaceobj.name)
+            self._apply_master_settings(ifaceobj)
+            # clag_enable has to happen before the slaves are added to the bond
+            self._set_clag_enable(ifaceobj)
+            self._add_slaves(ifaceobj)
+            self._apply_slaves_lacp_bypass_prio(ifaceobj)
+            if ifaceobj.addr_method == 'manual':
+               rtnetlink_api.rtnl_api.link_set(ifaceobj.name, "up")
+        except Exception, e:
+            self.log_error(str(e))
+
+    def _down(self, ifaceobj):
+        try:
+            self.ifenslavecmd.delete_bond(ifaceobj.name)
+        except Exception, e:
+            self.log_warn(str(e))
+
+    def _query_check(self, ifaceobj, ifaceobjcurr):
+        slaves = None
+
+        if not self.ifenslavecmd.bond_exists(ifaceobj.name):
+            self.logger.debug('bond iface %s' %ifaceobj.name +
+                              ' does not exist')
+            return
+
+        ifaceattrs = self.dict_key_subset(ifaceobj.config,
+                                          self.get_mod_attrs())
+        if not ifaceattrs: return
+        runningattrs = self._query_running_attrs(ifaceobj.name)
+
+        # backward compat change
+        runningattrs.update({'bond-lacp-fallback-allow': runningattrs.get(
+                                                    'bond-lacp-bypass-allow'),
+                          'bond-lacp-fallback-period': runningattrs.get(
+                                                    'bond-lacp-bypass-period'),
+                          'bond-lacp-fallback-priority': runningattrs.get(
+                                                'bond-lacp-bypass-priority')})
+        for k in ifaceattrs:
+            v = ifaceobj.get_attr_value_first(k)
+            if not v:
+                continue
+            if k == 'bond-slaves':
+                slaves = self._get_slave_list(ifaceobj)
+                continue
+            rv = runningattrs.get(k)
+            if not rv:
+                ifaceobjcurr.update_config_with_status(k, 'None', 1)
+            else:
+                if (k == 'bond-lacp-bypass-priority' or
+                    k == 'bond-lacp-fallback-priority'):
+                    prios = v.split()
+                    prios.sort()
+                    prio_str = ' '.join(prios)
+                    ifaceobjcurr.update_config_with_status(k, rv,
+                                    1 if prio_str != rv else 0)
+                    continue
+                ifaceobjcurr.update_config_with_status(k, rv,
+                                                       1 if v != rv else 0)
+        runningslaves = runningattrs.get('bond-slaves')
+        if not slaves and not runningslaves:
+            return
+        retslave = 1
+        if slaves and runningslaves:
+            if slaves and runningslaves:
+                difference = set(slaves).symmetric_difference(runningslaves)
+                if not difference:
+                    retslave = 0
+        ifaceobjcurr.update_config_with_status('bond-slaves',
+                        ' '.join(runningslaves)
+                        if runningslaves else 'None', retslave)
+
+    def _query_running_attrs(self, bondname):
+        bondattrs = {'bond-mode' :
+                            self.ifenslavecmd.get_mode(bondname),
+                     'bond-miimon' :
+                            self.ifenslavecmd.get_miimon(bondname),
+                     'bond-use-carrier' :
+                            self.ifenslavecmd.get_use_carrier(bondname),
+                     'bond-lacp-rate' :
+                            self.ifenslavecmd.get_lacp_rate(bondname),
+                     'bond-min-links' :
+                            self.ifenslavecmd.get_min_links(bondname),
+                     'bond-ad-sys-mac-addr' :
+                            self.ifenslavecmd.get_ad_sys_mac_addr(bondname),
+                     'bond-ad-sys-priority' :
+                            self.ifenslavecmd.get_ad_sys_priority(bondname),
+                     'bond-xmit-hash-policy' :
+                            self.ifenslavecmd.get_xmit_hash_policy(bondname),
+                     'bond-lacp-bypass-allow' :
+                            self.ifenslavecmd.get_lacp_fallback_allow(bondname),
+                     'bond-lacp-bypass-period' :
+                            self.ifenslavecmd.get_lacp_fallback_period(bondname),
+                     'bond-lacp-bypass-priority' :
+                            self.ifenslavecmd.get_lacp_fallback_priority(bondname)}
+        slaves = self.ifenslavecmd.get_slaves(bondname)
+        if slaves:
+            bondattrs['bond-slaves'] = slaves
+        return bondattrs
+
+    def _query_running(self, ifaceobjrunning):
+        if not self.ifenslavecmd.bond_exists(ifaceobjrunning.name):
+            return
+        bondattrs = self._query_running_attrs(ifaceobjrunning.name)
+        if bondattrs.get('bond-slaves'):
+            bondattrs['bond-slaves'] = ' '.join(bondattrs.get('bond-slaves'))
+        [ifaceobjrunning.update_config(k, v)
+                    for k, v in bondattrs.items()
+                        if v and v != self.get_mod_subattr(k, 'default')]
+
+    _run_ops = {'pre-up' : _up,
+               'post-down' : _down,
+               'query-running' : _query_running,
+               'query-checkcurr' : _query_check}
+
+    def get_ops(self):
+        """ returns list of ops supported by this module """
+        return self._run_ops.keys()
+
+    def _init_command_handlers(self):
+        flags = self.get_flags()
+        if not self.ipcmd:
+            self.ipcmd = iproute2(**flags)
+        if not self.ifenslavecmd:
+            self.ifenslavecmd = ifenslaveutil(**flags)
+
+    def run(self, ifaceobj, operation, query_ifaceobj=None, **extra_args):
+        """ run bond configuration on the interface object passed as argument
+
+        Args:
+            **ifaceobj** (object): iface object
+
+            **operation** (str): any of 'pre-up', 'post-down', 'query-checkcurr',
+                'query-running'
+
+        Kwargs:
+            **query_ifaceobj** (object): query check ifaceobject. This is only
+                valid when op is 'query-checkcurr'. It is an object same as
+                ifaceobj, but contains running attribute values and its config
+                status. The modules can use it to return queried running state
+                of interfaces. status is success if the running state is same
+                as user required state in ifaceobj. error otherwise.
+        """
+        op_handler = self._run_ops.get(operation)
+        if not op_handler:
+            return
+        if operation != 'query-running' and not self._is_bond(ifaceobj):
+            return
+        self._init_command_handlers()
+        if operation == 'query-checkcurr':
+            op_handler(self, ifaceobj, query_ifaceobj)
+        else:
+            op_handler(self, ifaceobj)
diff --git a/addons/loopback.py b/addons/loopback.py
new file mode 100644 (file)
index 0000000..dd35917
--- /dev/null
@@ -0,0 +1,63 @@
+#!/usr/bin/python
+
+# This should be pretty simple and might not really even need to exist.
+# The key is that we need to call link_create with a type of "dummy"
+# since that will translate to 'ip link add loopbackX type dummy'
+# The config file should probably just indicate that the type is
+# loopback or dummy.
+
+from ifupdown.iface import *
+from ifupdownaddons.modulebase import moduleBase
+from ifupdownaddons.iproute2 import iproute2
+import logging
+
+class loopback(moduleBase):
+    _modinfo = {'mhelp' : 'configure extra loopback module based on ' +
+                         'dummy device' }
+
+    def __init__(self, *args, **kargs):
+        moduleBase.__init__(self, *args, **kargs)
+        self.ipcmd = None
+
+    def _is_loopback_by_name(self, ifacename):
+        return 'loop' in ifacename
+
+    def _up(self, ifaceobj):
+        if self._is_loopback_by_name(ifaceobj.name):
+           self.ipcmd.link_create(ifaceobj.name, 'dummy')
+
+    def _down(self, ifaceobj):
+        if not self.PERFMODE and not self.ipcmd.link_exists(ifaceobj.name):
+           return
+        try:
+            self.ipcmd.link_delete(ifaceobj.name)
+        except Exception, e:
+            self.log_warn(str(e))
+
+    def _query_check(self, ifaceobj, ifaceobjcurr):
+        if not self.ipcmd.link_exists(ifaceobj.name):
+           return
+
+    _run_ops = {'pre-up' : _up,
+               'post-down' : _down,
+               'query-checkcurr' : _query_check}
+
+    def get_ops(self):
+        return self._run_ops.keys()
+
+    def _init_command_handlers(self):
+        if not self.ipcmd:
+            self.ipcmd = iproute2(**self.get_flags())
+
+    def run(self, ifaceobj, operation, query_ifaceobj=None, **extra_args):
+        op_handler = self._run_ops.get(operation)
+        if not op_handler:
+            return
+        if (operation != 'query-running' and
+                not self._is_loopback_by_name(ifaceobj.name)):
+            return
+        self._init_command_handlers()
+        if operation == 'query-checkcurr':
+            op_handler(self, ifaceobj, query_ifaceobj)
+        else:
+            op_handler(self, ifaceobj)
diff --git a/addons/mstpctl.py b/addons/mstpctl.py
new file mode 100644 (file)
index 0000000..bc2cd07
--- /dev/null
@@ -0,0 +1,771 @@
+#!/usr/bin/python
+#
+# Copyright 2014 Cumulus Networks, Inc. All rights reserved.
+# Author: Roopa Prabhu, roopa@cumulusnetworks.com
+#
+
+from sets import Set
+from ifupdown.iface import *
+from ifupdownaddons.modulebase import moduleBase
+from ifupdownaddons.bridgeutils import brctl
+from ifupdownaddons.iproute2 import iproute2
+from ifupdownaddons.mstpctlutil import mstpctlutil
+import traceback
+
+class mstpctlFlags:
+    PORT_PROCESSED = 0x1
+
+class mstpctl(moduleBase):
+    """  ifupdown2 addon module to configure mstp attributes """
+
+    _modinfo = {'mhelp' : 'mstp configuration module for bridges',
+                'attrs' : {
+                   'mstpctl-ports' :
+                        {'help' : 'mstp ports',
+                         'compat' : True},
+                   'mstpctl-stp' :
+                        {'help': 'bridge stp yes/no',
+                         'compat' : True,
+                         'default' : 'no'},
+                   'mstpctl-treeprio' :
+                        {'help': 'tree priority',
+                         'default' : '32768',
+                         'validrange' : ['0', '65535'],
+                         'required' : False,
+                         'example' : ['mstpctl-treeprio 32768']},
+                   'mstpctl-ageing' :
+                        {'help': 'ageing time',
+                         'default' : '300',
+                         'required' : False,
+                         'example' : ['mstpctl-ageing 300']},
+                    'mstpctl-maxage' :
+                        { 'help' : 'max message age',
+                          'default' : '20',
+                          'required' : False,
+                          'example' : ['mstpctl-maxage 20']},
+                    'mstpctl-fdelay' :
+                        { 'help' : 'set forwarding delay',
+                          'default' : '15',
+                          'required' : False,
+                          'example' : ['mstpctl-fdelay 15']},
+                    'mstpctl-maxhops' :
+                        { 'help' : 'bridge max hops',
+                          'default' : '15',
+                          'required' : False,
+                          'example' : ['mstpctl-maxhops 15']},
+                    'mstpctl-txholdcount' :
+                        { 'help' : 'bridge transmit holdcount',
+                          'default' : '6',
+                          'required' : False,
+                          'example' : ['mstpctl-txholdcount 6']},
+                    'mstpctl-forcevers' :
+                        { 'help' : 'bridge force stp version',
+                          'default' : 'rstp',
+                          'required' : False,
+                          'example' : ['mstpctl-forcevers rstp']},
+                    'mstpctl-portpathcost' :
+                        { 'help' : 'bridge port path cost',
+                          'default' : '0',
+                          'required' : False,
+                          'example' : ['mstpctl-portpathcost swp1=0 swp2=1']},
+                    'mstpctl-portp2p' :
+                        { 'help' : 'bridge port p2p detection mode',
+                          'default' : 'auto',
+                          'validvals' : ['yes', 'no', 'auto'],
+                          'required' : False,
+                          'example' : ['mstpctl-portp2p swp1=no swp2=no']},
+                    'mstpctl-portrestrrole' :
+                        { 'help' :
+                          'enable/disable port ability to take root role of the port',
+                          'default' : 'no',
+                          'validvals' : ['yes', 'no'],
+                          'required' : False,
+                          'example' : ['mstpctl-portrestrrole swp1=no swp2=no']},
+                    'mstpctl-portrestrtcn' :
+                        { 'help' :
+                          'enable/disable port ability to propagate received topology change notification of the port',
+                          'default' : 'no',
+                          'validvals' : ['yes', 'no'],
+                          'required' : False,
+                          'example' : ['mstpctl-portrestrtcn swp1=no swp2=no']},
+                    'mstpctl-bpduguard' :
+                        { 'help' :
+                          'enable/disable bpduguard',
+                          'default' : 'no',
+                          'validvals' : ['yes', 'no'],
+                          'required' : False,
+                          'example' : ['mstpctl-bpduguard swp1=no swp2=no']},
+                    'mstpctl-treeportprio' : 
+                        { 'help' :
+                          'port priority for MSTI instance',
+                          'default' : '128',
+                          'validrange' : ['0', '240'],
+                          'required' : False,
+                          'example' : ['mstpctl-treeportprio swp1=128 swp2=128']},
+                    'mstpctl-hello' :
+                        { 'help' : 'set hello time',
+                          'default' : '2',
+                          'required' : False,
+                          'example' : ['mstpctl-hello 2']},
+                    'mstpctl-portnetwork' : 
+                        { 'help' : 'enable/disable bridge assurance capability for a port',
+                          'validvals' : ['yes', 'no'],
+                          'default' : 'no',
+                          'required' : False,
+                          'example' : ['mstpctl-portnetwork swp1=no swp2=no']},
+                    'mstpctl-portadminedge' : 
+                        { 'help' : 'enable/disable initial edge state of the port',
+                          'validvals' : ['yes', 'no'],
+                          'default' : 'no',
+                          'required' : False,
+                          'example' : ['mstpctl-portadminedge swp1=no swp2=no']},
+                    'mstpctl-portautoedge' : 
+                        { 'help' : 'enable/disable auto transition to/from edge state of the port',
+                          'validvals' : ['yes', 'no'],
+                          'default' : 'yes',
+                          'required' : False,
+                          'example' : ['mstpctl-portautoedge swp1=yes swp2=yes']},
+                    'mstpctl-treeportcost' : 
+                        { 'help' : 'port tree cost',
+                          'required' : False},
+                    'mstpctl-portbpdufilter' : 
+                        { 'help' : 'enable/disable bpdu filter on a port. ' +
+                                'syntax varies when defined under a bridge ' +
+                                'vs under a port',
+                          'validvals' : ['yes', 'no'],
+                          'default' : 'no',
+                          'required' : False,
+                          'example' : ['under a bridge: mstpctl-portbpdufilter swp1=no swp2=no',
+                                       'under a port: mstpctl-portbpdufilter yes']},
+                        }}
+
+    # Maps mstp bridge attribute names to corresponding mstpctl commands
+    # XXX: This can be encoded in the modules dict above
+    _attrs_map = OrderedDict([('mstpctl-treeprio' , 'treeprio'),
+                  ('mstpctl-ageing' , 'ageing'),
+                  ('mstpctl-maxage' , 'maxage'),
+                  ('mstpctl-fdelay' , 'fdelay'),
+                  ('mstpctl-maxhops' , 'maxhops'),
+                  ('mstpctl-txholdcount' , 'txholdcount'),
+                  ('mstpctl-forcevers', 'forcevers'),
+                  ('mstpctl-hello' , 'hello')])
+
+    # Maps mstp port attribute names to corresponding mstpctl commands
+    # XXX: This can be encoded in the modules dict above
+    _port_attrs_map = {'mstpctl-portpathcost' : 'portpathcost',
+                 'mstpctl-portadminedge' : 'portadminedge',
+                 'mstpctl-portautoedge' : 'portautoedge' ,
+                 'mstpctl-portp2p' : 'portp2p',
+                 'mstpctl-portrestrrole' : 'portrestrrole',
+                 'mstpctl-portrestrtcn' : 'portrestrtcn',
+                 'mstpctl-bpduguard' : 'bpduguard',
+                 'mstpctl-treeportprio' : 'treeportprio',
+                 'mstpctl-treeportcost' : 'treeportcost',
+                 'mstpctl-portnetwork' : 'portnetwork',
+                 'mstpctl-portbpdufilter' : 'portbpdufilter'}
+
+    def __init__(self, *args, **kargs):
+        moduleBase.__init__(self, *args, **kargs)
+        self.ipcmd = None
+        self.name = self.__class__.__name__
+        self.brctlcmd = None
+        self.mstpctlcmd = None
+
+    def _is_bridge(self, ifaceobj):
+        if (ifaceobj.get_attr_value_first('mstpctl-ports') or
+                ifaceobj.get_attr_value_first('bridge-ports')):
+            return True
+        return False
+
+    def _is_bridge_port(self, ifaceobj):
+        if self.brctlcmd.is_bridge_port(ifaceobj.name):
+            return True
+        return False
+
+    def get_dependent_ifacenames(self, ifaceobj, ifacenames_all=None):
+        if not self._is_bridge(ifaceobj):
+            return None
+        return self.parse_port_list(ifaceobj.get_attr_value_first(
+                                    'mstpctl-ports'), ifacenames_all)
+
+    def get_dependent_ifacenames_running(self, ifaceobj):
+        self._init_command_handlers()
+        if (self.brctlcmd.bridge_exists(ifaceobj.name) and
+                not self.mstpctlcmd.mstpbridge_exists(ifaceobj.name)):
+            return None
+        return self.brctlcmd.get_bridge_ports(ifaceobj.name)
+
+    def _get_bridge_port_list(self, ifaceobj):
+
+        # port list is also available in the previously
+        # parsed dependent list. Use that if available, instead
+        # of parsing port expr again
+        port_list = ifaceobj.lowerifaces
+        if port_list:
+            return port_list
+        ports = ifaceobj.get_attr_value_first('mstpctl-ports')
+        if ports:
+            return self.parse_port_list(ports)
+        else:
+            return None
+
+    def _ports_enable_disable_ipv6(self, ports, enable='1'):
+        for p in ports:
+            try:
+                self.write_file('/proc/sys/net/ipv6/conf/%s' %p +
+                                '/disable_ipv6', enable)
+            except Exception, e:
+                self.logger.info(str(e))
+                pass
+
+    def _add_ports(self, ifaceobj):
+        bridgeports = self._get_bridge_port_list(ifaceobj)
+
+        runningbridgeports = []
+        # Delete active ports not in the new port list
+        if not self.PERFMODE:
+            runningbridgeports = self.brctlcmd.get_bridge_ports(ifaceobj.name)
+            if runningbridgeports:
+                [self.ipcmd.link_set(bport, 'nomaster')
+                    for bport in runningbridgeports
+                        if not bridgeports or bport not in bridgeports]
+            else:
+                runningbridgeports = []
+        if not bridgeports:
+            return
+        err = 0
+        for bridgeport in Set(bridgeports).difference(Set(runningbridgeports)):
+            try:
+                if not self.DRYRUN and not self.ipcmd.link_exists(bridgeport):
+                    self.log_warn('%s: bridge port %s does not exist'
+                            %(ifaceobj.name, bridgeport))
+                    err += 1
+                    continue
+                self.ipcmd.link_set(bridgeport, 'master', ifaceobj.name)
+                self.ipcmd.addr_flush(bridgeport)
+            except Exception, e:
+                self.log_error(str(e))
+
+        if err:
+            self.log_error('error configuring bridge (missing ports)')
+
+    def _apply_bridge_settings(self, ifaceobj):
+        check = False if self.PERFMODE else True
+        try:
+            # set bridge attributes
+            for attrname, dstattrname in self._attrs_map.items():
+                try:
+                    v = ifaceobj.get_attr_value_first(attrname)
+                    if not v:
+                       continue
+                    if attrname == 'mstpctl-treeprio':
+                       self.mstpctlcmd.set_bridge_treeprio(ifaceobj.name,
+                                v, check)
+                    else:
+                       self.mstpctlcmd.set_bridge_attr(ifaceobj.name,
+                                dstattrname, v, check)
+                except Exception, e:
+                    self.logger.warn('%s' %str(e))
+                    pass
+
+            # set bridge port attributes
+            for attrname, dstattrname in self._port_attrs_map.items():
+                attrval = ifaceobj.get_attr_value_first(attrname)
+                if not attrval:
+                    continue
+                portlist = self.parse_port_list(attrval)
+                if not portlist:
+                    self.log_warn('%s: error parsing \'%s %s\''
+                         %(ifaceobj.name, attrname, attrval))
+                    continue
+                for p in portlist:
+                    try:
+                        (port, val) = p.split('=')
+                        self.mstpctlcmd.set_bridgeport_attr(ifaceobj.name,
+                                port, dstattrname, val, check)
+                    except Exception, e:
+                        self.log_warn('%s: error setting %s (%s)'
+                                %(ifaceobj.name, attrname, str(e)))
+        except Exception, e:
+            self.log_warn(str(e))
+            pass
+
+    def _apply_bridge_port_settings(self, ifaceobj, bridgename=None,
+                                    bridgeifaceobj=None, stp_on=True,
+                                    mstpd_running=True):
+        check = False if self.PERFMODE else True
+        if not bridgename and bridgeifaceobj:
+            bridgename = bridgeifaceobj.name
+        # set bridge port attributes
+        for attrname, dstattrname in self._port_attrs_map.items():
+            attrval = ifaceobj.get_attr_value_first(attrname)
+            if not attrval:
+               #if bridgeifaceobj:
+               #   # If bridge object available, check if the bridge
+               #   # has the attribute set, in which case,
+               #   # inherit it from the bridge
+               #   attrval = bridgeifaceobj.get_attr_value_first(attrname)
+               #   if not attrval:
+               #      continue
+               #else:
+               continue
+            if not stp_on:
+               self.logger.warn('%s: cannot set %s (stp on bridge %s not on)\n'
+                       %(ifaceobj.name, attrname, bridgename))
+               continue
+            if not mstpd_running:
+               continue
+            try:
+               self.mstpctlcmd.set_bridgeport_attr(bridgename,
+                           ifaceobj.name, dstattrname, attrval, check)
+            except Exception, e:
+               self.log_warn('%s: error setting %s (%s)'
+                             %(ifaceobj.name, attrname, str(e)))
+
+    def _apply_bridge_port_settings_all(self, ifaceobj,
+                                        ifaceobj_getfunc=None):
+        self.logger.info('%s: applying mstp configuration '
+                          %ifaceobj.name + 'specific to ports')
+        # Query running bridge ports. and only apply attributes on them
+        bridgeports = self.brctlcmd.get_bridge_ports(ifaceobj.name)
+        if not bridgeports:
+           self.logger.debug('%s: cannot find bridgeports' %ifaceobj.name)
+           return
+        for bport in bridgeports:
+            self.logger.info('%s: processing mstp config for port %s'
+                             %(ifaceobj.name, bport))
+            if not self.ipcmd.link_exists(bport):
+               continue
+            bportifaceobjlist = ifaceobj_getfunc(bport)
+            if not bportifaceobjlist:
+               continue
+            for bportifaceobj in bportifaceobjlist:
+                # Dont process bridge port if it already has been processed
+                if (bportifaceobj.module_flags.get(self.name,0x0) & \
+                    mstpctlFlags.PORT_PROCESSED):
+                    continue
+                try:
+                    self._apply_bridge_port_settings(bportifaceobj, 
+                                            ifaceobj.name, ifaceobj)
+                except Exception, e:
+                    self.log_warn(str(e))
+
+    def _up(self, ifaceobj, ifaceobj_getfunc=None):
+        # Check if bridge port
+        bridgename = self.ipcmd.bridge_port_get_bridge_name(ifaceobj.name)
+        if bridgename:
+            mstpd_running = (True if self.mstpctlcmd.is_mstpd_running()
+                             else False)
+            stp_on = (True if self.read_file_oneline(
+                      '/sys/class/net/%s/bridge/stp_state'
+                      %bridgename) == '2' else False)
+            self._apply_bridge_port_settings(ifaceobj, bridgename, None,
+                                             stp_on, mstpd_running)
+            ifaceobj.module_flags[self.name] = ifaceobj.module_flags.setdefault(self.name,0) | \
+                                               mstpctlFlags.PORT_PROCESSED
+            return
+        if not self._is_bridge(ifaceobj):
+            return
+        stp = None
+        try:
+            porterr = False
+            porterrstr = ''
+            if ifaceobj.get_attr_value_first('mstpctl-ports'):
+                # If bridge ports specified with mstpctl attr, create the
+                # bridge and also add its ports
+                self.ipcmd.batch_start()
+                if not self.PERFMODE:
+                    if not self.ipcmd.link_exists(ifaceobj.name):
+                        self.ipcmd.link_create(ifaceobj.name, 'bridge')
+                else:
+                    self.ipcmd.link_create(ifaceobj.name, 'bridge')
+                try:
+                    self._add_ports(ifaceobj)
+                except Exception, e:
+                    porterr = True
+                    porterrstr = str(e)
+                    pass
+                finally:
+                    self.ipcmd.batch_commit()
+            running_ports = self.brctlcmd.get_bridge_ports(ifaceobj.name)
+            if running_ports:
+                # disable ipv6 for ports that were added to bridge
+                self._ports_enable_disable_ipv6(running_ports, '1')
+
+            stp = ifaceobj.get_attr_value_first('mstpctl-stp')
+            if stp:
+               self.set_iface_attr(ifaceobj, 'mstpctl-stp',
+                                    self.brctlcmd.set_stp)
+            else:
+               stp = self.brctlcmd.get_stp(ifaceobj.name)
+            if (self.mstpctlcmd.is_mstpd_running() and
+                    (stp == 'yes' or stp == 'on')):
+                self._apply_bridge_settings(ifaceobj)
+                self._apply_bridge_port_settings_all(ifaceobj,
+                            ifaceobj_getfunc=ifaceobj_getfunc)
+        except Exception, e:
+            self.log_error(str(e))
+        if porterr:
+            raise Exception(porterrstr)
+
+    def _down(self, ifaceobj, ifaceobj_getfunc=None):
+        if not self._is_bridge(ifaceobj):
+            return
+        try:
+            if ifaceobj.get_attr_value_first('mstpctl-ports'):
+                # If bridge ports specified with mstpctl attr, delete the
+                # bridge
+                ports = self.brctlcmd.get_bridge_ports(ifaceobj.name)
+                if ports:
+                    self._ports_enable_disable_ipv6(ports, '0')
+                self.brctlcmd.delete_bridge(ifaceobj.name)
+        except Exception, e:
+            self.log_error(str(e))
+
+    def _query_running_attrs(self, ifaceobjrunning):
+        bridgeattrdict = {}
+
+        tmpbridgeattrdict = self.mstpctlcmd.get_bridge_attrs(ifaceobjrunning.name)
+        if not tmpbridgeattrdict:
+            return bridgeattrdict
+
+        for k,v in tmpbridgeattrdict.items():
+            if k == 'stp' or not v:
+                continue
+            if k == 'ports':
+                ports = v.keys()
+                continue
+            attrname = 'mstpctl-' + k
+            if v and v != self.get_mod_subattr(attrname, 'default'):
+                bridgeattrdict[attrname] = [v]
+
+        ports = self.brctlcmd.get_bridge_ports(ifaceobjrunning.name)
+        if ports:
+            portconfig = {'mstpctl-portnetwork' : '',
+                          'mstpctl-portpathcost' : '',
+                          'mstpctl-portadminedge' : '',
+                          'mstpctl-portautoedge' : '',
+                          'mstpctl-portp2p' : '',
+                          'mstpctl-portrestrrole' : '',
+                          'mstpctl-portrestrtcn' : '',
+                          'mstpctl-bpduguard' : '',
+                          'mstpctl-treeportprio' : '',
+                          'mstpctl-treeportcost' : ''}
+
+            for p in ports:
+                v = self.mstpctlcmd.get_bridgeport_attr(ifaceobjrunning.name,
+                            p, 'portnetwork')
+                if v and v != 'no':
+                    portconfig['mstpctl-portnetwork'] += ' %s=%s' %(p, v)
+
+                # XXX: Can we really get path cost of a port ???
+                #v = self.mstpctlcmd.get_portpathcost(ifaceobjrunning.name, p)
+                #if v and v != self.get_mod_subattr('mstpctl-portpathcost',
+                #                                   'default'):
+                #    portconfig['mstpctl-portpathcost'] += ' %s=%s' %(p, v)
+
+                v = self.mstpctlcmd.get_bridgeport_attr(ifaceobjrunning.name,
+                            p, 'portadminedge')
+                if v and v != 'no':
+                    portconfig['mstpctl-portadminedge'] += ' %s=%s' %(p, v)
+
+                v = self.mstpctlcmd.get_bridgeport_attr(ifaceobjrunning.name,
+                            p, 'portp2p')
+                if v and v != 'no':
+                    portconfig['mstpctl-portp2p'] += ' %s=%s' %(p, v)
+
+                v = self.mstpctlcmd.get_bridgeport_attr(ifaceobjrunning.name,
+                            p, 'portrestrrole')
+                if v and v != 'no':
+                    portconfig['mstpctl-portrestrrole'] += ' %s=%s' %(p, v)
+
+                v = self.mstpctlcmd.get_bridgeport_attr(ifaceobjrunning.name,
+                            p, 'portrestrtcn')
+                if v and v != 'no':
+                    portconfig['mstpctl-portrestrtcn'] += ' %s=%s' %(p, v)
+
+                v = self.mstpctlcmd.get_bridgeport_attr(ifaceobjrunning.name,
+                            p, 'bpduguard')
+                if v and v != 'no':
+                    portconfig['mstpctl-bpduguard'] += ' %s=%s' %(p, v)
+
+                # XXX: Can we really get path cost of a port ???
+                #v = self.mstpctlcmd.get_bridgeport_attr(ifaceobjrunning.name,
+                #            p, 'treeprio')
+                #if v and v != self.get_mod_subattr('mstpctl-treeportprio',
+                #                                   'default'):
+                #    portconfig['mstpctl-treeportprio'] += ' %s=%s' %(p, v)
+
+                #v = self.mstpctlcmd.get_bridgeport_attr(ifaceobjrunning.name,
+                #            p, 'treecost')
+                #if v and v != self.get_mod_subattr('mstpctl-treeportcost',
+                #                                   'default'):
+                #    portconfig['mstpctl-treeportcost'] += ' %s=%s' %(p, v)
+
+            bridgeattrdict.update({k : [v] for k, v in portconfig.items()
+                                    if v})
+        return bridgeattrdict
+
+    def _query_check_bridge(self, ifaceobj, ifaceobjcurr):
+        # list of attributes that are not supported currently
+        blacklistedattrs = ['mstpctl-portpathcost',
+                'mstpctl-treeportprio', 'mstpctl-treeportcost']
+        if not self.brctlcmd.bridge_exists(ifaceobj.name):
+            self.logger.debug('bridge %s does not exist' %ifaceobj.name)
+            return
+        ifaceattrs = self.dict_key_subset(ifaceobj.config,
+                                          self.get_mod_attrs())
+        if not ifaceattrs:
+            return
+        runningattrs = self.mstpctlcmd.get_bridge_attrs(ifaceobj.name)
+        if not runningattrs:
+            runningattrs = {}
+        for k in ifaceattrs:
+            # for all mstpctl options
+            if k in blacklistedattrs:
+                continue
+            # get the corresponding ifaceobj attr
+            v = ifaceobj.get_attr_value_first(k)
+            if not v:
+                continue
+
+            # Get the running attribute
+            rv = runningattrs.get(k[8:])
+            if k == 'mstpctl-stp':
+                # special case stp compare because it may
+                # contain more than one valid values
+                stp_on_vals = ['on', 'yes']
+                stp_off_vals = ['off']
+                rv = self.brctlcmd.get_stp(ifaceobj.name)
+                if ((v in stp_on_vals and rv in stp_on_vals) or
+                    (v in stp_off_vals and rv in stp_off_vals)):
+                    ifaceobjcurr.update_config_with_status('mstpctl-stp', v, 0)
+                else:
+                    ifaceobjcurr.update_config_with_status('mstpctl-stp', v, 1)
+                continue
+
+            if k == 'mstpctl-ports':
+                # special case ports because it can contain regex or glob
+                # XXX: We get all info from mstputils, which means if
+                # mstpd is down, we will not be returning any bridge bridgeports
+                running_port_list = self.brctlcmd.get_bridge_ports(ifaceobj.name)
+                bridge_port_list = self._get_bridge_port_list(ifaceobj)
+                if not running_port_list and not bridge_port_list:
+                    continue
+                portliststatus = 1
+                if running_port_list and bridge_port_list:
+                    difference = Set(running_port_list).symmetric_difference(
+                                                        Set(bridge_port_list))
+                    if not difference:
+                        portliststatus = 0
+                ifaceobjcurr.update_config_with_status('mstpctl-ports',
+                    ' '.join(running_port_list)
+                    if running_port_list else '', portliststatus)
+            elif k[:12] == 'mstpctl-port' or k == 'mstpctl-bpduguard':
+                # Now, look at port attributes
+                # derive the mstpctlcmd attr name
+                #mstpctlcmdattrname = k[12:] if k[:12] == 'mstpctl-port' else k[8:]
+                mstpctlcmdattrname = k[8:]
+
+                # for port attributes, the attributes are in a list
+                # <portname>=<portattrvalue>
+                status = 0
+                currstr = ''
+                vlist = self.parse_port_list(v)
+                if not vlist:
+                    continue
+                for vlistitem in vlist:
+                    try:
+                        (p, v) = vlistitem.split('=')
+                        currv = self.mstpctlcmd.get_bridgeport_attr(
+                                        ifaceobj.name, p, mstpctlcmdattrname)
+                        if currv:
+                            currstr += ' %s=%s' %(p, currv)
+                        else:
+                            currstr += ' %s=%s' %(p, 'None')
+                        if currv != v:
+                            status = 1
+                    except Exception, e:
+                        self.log_warn(str(e))
+                        pass
+                ifaceobjcurr.update_config_with_status(k, currstr, status)
+            elif not rv:
+                ifaceobjcurr.update_config_with_status(k, '', 1)
+            elif v != rv:
+                ifaceobjcurr.update_config_with_status(k, rv, 1)
+            else:
+                ifaceobjcurr.update_config_with_status(k, rv, 0)
+
+    def _query_check_bridge_port(self, ifaceobj, ifaceobjcurr):
+        if not self.ipcmd.link_exists(ifaceobj.name):
+            #self.logger.debug('bridge port %s does not exist' %ifaceobj.name)
+            ifaceobjcurr.status = ifaceStatus.NOTFOUND
+            return
+        # Check if this is a bridge port
+        if not self._is_bridge_port(ifaceobj):
+            # mark all the bridge attributes as error
+            ifaceobjcurr.check_n_update_config_with_status_many(ifaceobj,
+                            self._port_attrs_map.keys(), 0)
+            return
+        bridgename = self.ipcmd.bridge_port_get_bridge_name(ifaceobj.name)
+        # list of attributes that are not supported currently
+        blacklistedattrs = ['mstpctl-portpathcost',
+                'mstpctl-treeportprio', 'mstpctl-treeportcost']
+        ifaceattrs = self.dict_key_subset(ifaceobj.config,
+                                          self._port_attrs_map.keys())
+        if not ifaceattrs:
+            return
+        runningattrs = self.mstpctlcmd.get_bridge_attrs(ifaceobj.name)
+        if not runningattrs:
+            runningattrs = {}
+        for k in ifaceattrs:
+            # for all mstpctl options
+            # get the corresponding ifaceobj attr
+            v = ifaceobj.get_attr_value_first(k)
+            if not v or k in blacklistedattrs:
+                ifaceobjcurr.update_config_with_status(k, v, -1)
+                continue
+            currv = self.mstpctlcmd.get_bridgeport_attr(bridgename,
+                             ifaceobj.name, self._port_attrs_map.get(k))
+            if currv:
+                if currv != v:
+                    ifaceobjcurr.update_config_with_status(k, currv, 1)
+                else:
+                    ifaceobjcurr.update_config_with_status(k, currv, 0)
+            else:
+                ifaceobjcurr.update_config_with_status(k, None, 1)
+
+    def _query_check(self, ifaceobj, ifaceobjcurr, ifaceobj_getfunc=None):
+        if self._is_bridge(ifaceobj):
+            self._query_check_bridge(ifaceobj, ifaceobjcurr)
+        else:
+            self._query_check_bridge_port(ifaceobj, ifaceobjcurr)
+
+    def _query_running_bridge_port(self, ifaceobjrunning):
+        bridgename = self.ipcmd.bridge_port_get_bridge_name(
+                                ifaceobjrunning.name)
+        if not bridgename:
+            self.logger.warn('%s: unable to determine bridgename'
+                             %ifaceobjrunning.name)
+            return
+        if self.brctlcmd.get_stp(bridgename) == 'no':
+           # This bridge does not run stp, return
+           return
+        # if userspace stp not set, return
+        if self.sysctl_get('net.bridge.bridge-stp-user-space') != '1':
+           return
+        v = self.mstpctlcmd.get_bridgeport_attr(bridgename,
+                                                ifaceobjrunning.name,
+                                                'portnetwork')
+        if v and v != 'no':
+           ifaceobjrunning.update_config('mstpctl-network', v)
+
+        # XXX: Can we really get path cost of a port ???
+        #v = self.mstpctlcmd.get_portpathcost(ifaceobjrunning.name, p)
+        #if v and v != self.get_mod_subattr('mstpctl-pathcost',
+        #                                   'default'):
+        #   ifaceobjrunning.update_config('mstpctl-network', v)
+
+        v = self.mstpctlcmd.get_bridgeport_attr(bridgename,
+                          ifaceobjrunning.name, 'portadminedge')
+        if v and v != 'no':
+           ifaceobjrunning.update_config('mstpctl-portadminedge', v)
+
+        v = self.mstpctlcmd.get_bridgeport_attr(bridgename,
+                                       ifaceobjrunning.name,'portp2p')
+        if v and v != 'auto':
+           ifaceobjrunning.update_config('mstpctl-portp2p', v)
+
+        v = self.mstpctlcmd.get_bridgeport_attr(bridgename,
+                        ifaceobjrunning.name, 'portrestrrole')
+        if v and v != 'no':
+           ifaceobjrunning.update_config('mstpctl-portrestrrole', v)
+
+        v = self.mstpctlcmd.get_bridgeport_attr(bridgename,
+                            ifaceobjrunning.name, 'restrtcn')
+        if v and v != 'no':
+           ifaceobjrunning.update_config('mstpctl-portrestrtcn', v)
+
+        v = self.mstpctlcmd.get_bridgeport_attr(bridgename,
+                            ifaceobjrunning.name, 'bpduguard')
+        if v and v != 'no':
+           ifaceobjrunning.update_config('mstpctl-bpduguard', v)
+
+        # XXX: Can we really get path cost of a port ???
+        #v = self.mstpctlcmd.get_bridgeport_attr(ifaceobjrunning.name,
+        #            p, 'treeprio')
+        #if v and v != self.get_mod_subattr('mstpctl-treeportprio',
+        #                                   'default'):
+        #    portconfig['mstpctl-treeportprio'] += ' %s=%s' %(p, v)
+
+        #v = self.mstpctlcmd.get_bridgeport_attr(ifaceobjrunning.name,
+        #               p, 'treecost')
+        #if v and v != self.get_mod_subattr('mstpctl-treeportcost',
+        #                                   'default'):
+        #    portconfig['mstpctl-treeportcost'] += ' %s=%s' %(p, v)
+
+    def _query_running_bridge(self, ifaceobjrunning):
+        if self.brctlcmd.get_stp(ifaceobjrunning.name) == 'no':
+           # This bridge does not run stp, return
+           return
+        # if userspace stp not set, return
+        if self.sysctl_get('net.bridge.bridge-stp-user-space') != '1':
+           return
+        # Check if mstp really knows about this bridge
+        if not self.mstpctlcmd.mstpbridge_exists(ifaceobjrunning.name):
+            return
+        ifaceobjrunning.update_config_dict(self._query_running_attrs(
+                                           ifaceobjrunning))
+
+    def _query_running(self, ifaceobjrunning, **extra_args):
+        if self.brctlcmd.bridge_exists(ifaceobjrunning.name):
+            self._query_running_bridge(ifaceobjrunning)
+        elif self.brctlcmd.is_bridge_port(ifaceobjrunning.name):
+            self._query_running_bridge_port(ifaceobjrunning)
+
+    _run_ops = {'pre-up' : _up,
+               'post-down' : _down,
+               'query-checkcurr' : _query_check,
+               'query-running' : _query_running}
+
+    def get_ops(self):
+        """ returns list of ops supported by this module """
+        return self._run_ops.keys()
+
+    def _init_command_handlers(self):
+        flags = self.get_flags()
+        if not self.ipcmd:
+            self.ipcmd = iproute2(**flags)
+        if not self.brctlcmd:
+            self.brctlcmd = brctl(**flags)
+        if not self.mstpctlcmd:
+            self.mstpctlcmd = mstpctlutil(**flags)
+
+    def run(self, ifaceobj, operation, query_ifaceobj=None,
+            ifaceobj_getfunc=None, **extra_args):
+        """ run mstp configuration on the interface object passed as argument
+
+        Args:
+            **ifaceobj** (object): iface object
+
+            **operation** (str): any of 'pre-up', 'post-down', 'query-checkcurr',
+                                 'query-running'
+        Kwargs:
+            **query_ifaceobj** (object): query check ifaceobject. This is only
+                valid when op is 'query-checkcurr'. It is an object same as
+                ifaceobj, but contains running attribute values and its config
+                status. The modules can use it to return queried running state
+                of interfaces. status is success if the running state is same
+                as user required state in ifaceobj. error otherwise.
+        """
+        if ifaceobj.type == ifaceType.BRIDGE_VLAN:
+           return
+        op_handler = self._run_ops.get(operation)
+        if not op_handler:
+           return
+        self._init_command_handlers()
+        if operation == 'query-checkcurr':
+            op_handler(self, ifaceobj, query_ifaceobj,
+                       ifaceobj_getfunc=ifaceobj_getfunc)
+        else:
+            op_handler(self, ifaceobj, ifaceobj_getfunc=ifaceobj_getfunc)
diff --git a/addons/usercmds.py b/addons/usercmds.py
new file mode 100644 (file)
index 0000000..72915ea
--- /dev/null
@@ -0,0 +1,97 @@
+#!/usr/bin/python
+#
+# Copyright 2014 Cumulus Networks, Inc. All rights reserved.
+# Author: Roopa Prabhu, roopa@cumulusnetworks.com
+#
+
+import subprocess
+import ifupdownaddons
+
+class usercmds(ifupdownaddons.modulebase.moduleBase):
+    """  ifupdown2 addon module to configure user specified commands """
+
+    _modinfo = {'mhelp' : 'user commands for interfaces',
+                'attrs' : {
+                   'pre-up' :
+                        {'help' : 'run command before bringing the interface up'},
+                   'up' :
+                        {'help' : 'run command at interface bring up'},
+                   'post-up' :
+                        {'help' : 'run command after interface bring up'},
+                   'pre-down' :
+                        {'help' : 'run command before bringing the interface down'},
+                   'down' :
+                        {'help' : 'run command at interface down'},
+                   'post-down' :
+                        {'help' : 'run command after bringing interface down'}}}
+
+    def _exec_user_cmd(self, cmd):
+        """ exec's commands using subprocess Popen
+
+        special wrapper using use closefds=True and shell=True
+        for user commands
+        """
+
+        cmd_returncode = 0
+        try:
+            self.logger.info('executing %s' %cmd)
+            if self.DRYRUN:
+                return
+            ch = subprocess.Popen(cmd,
+                    stdout=subprocess.PIPE,
+                    shell=True,
+                    stderr=subprocess.STDOUT,
+                    close_fds=True)
+            cmd_returncode = ch.wait()
+            cmdout = ch.communicate()[0]
+        except Exception, e:
+            raise Exception('failed to execute cmd \'%s\' (%s)'
+                            %(cmd, str(e)))
+        if cmd_returncode != 0:
+            raise Exception(cmdout)
+        return cmdout
+
+    def _run_command(self, ifaceobj, op):
+        cmd_list = ifaceobj.get_attr_value(op)
+        if cmd_list:
+            for cmd in cmd_list:
+                self.logger.info('executing cmd \'%s\'' %cmd)
+                try:
+                    self._exec_user_cmd(cmd)
+                except Exception, e:
+                    if not self.ignore_error(str(e)):
+                        self.logger.warn('%s: %s cmd \'%s\' failed (%s)'
+                                %(ifaceobj.name, op, cmd, str(e).strip('\n')))
+                    pass
+
+    _run_ops = {'pre-up' : _run_command,
+               'pre-down' : _run_command,
+               'up' : _run_command,
+               'post-up' : _run_command,
+               'down' : _run_command,
+               'post-down' : _run_command}
+
+    def get_ops(self):
+        """ returns list of ops supported by this module """
+        return self._run_ops.keys()
+
+    def run(self, ifaceobj, operation, query_ifaceobj=None, **extra_args):
+        """ run user commands
+
+        Args:
+            **ifaceobj** (object): iface object
+
+            **operation** (str): list of ops
+
+        Kwargs:
+            **query_ifaceobj** (object): query check ifaceobject. This is only
+                valid when op is 'query-checkcurr'. It is an object same as
+                ifaceobj, but contains running attribute values and its config
+                status. The modules can use it to return queried running state
+                of interfaces. status is success if the running state is same
+                as user required state in ifaceobj. error otherwise.
+        """
+        op_handler = self._run_ops.get(operation)
+        if not op_handler:
+            return
+        op_handler(self, ifaceobj, operation)
diff --git a/addons/vlan.py b/addons/vlan.py
new file mode 100644 (file)
index 0000000..c877d55
--- /dev/null
@@ -0,0 +1,237 @@
+#!/usr/bin/python
+#
+# Copyright 2014 Cumulus Networks, Inc. All rights reserved.
+# Author: Roopa Prabhu, roopa@cumulusnetworks.com
+#
+
+from ifupdown.iface import *
+from ifupdownaddons.modulebase import moduleBase
+from ifupdownaddons.iproute2 import iproute2
+import ifupdown.rtnetlink_api as rtnetlink_api
+import logging
+import re
+
+class vlan(moduleBase):
+    """  ifupdown2 addon module to configure vlans """
+
+    _modinfo = {'mhelp' : 'vlan module configures vlan interfaces.' +
+                        'This module understands vlan interfaces with dot ' +
+                        'notations. eg swp1.100. Vlan interfaces with any ' +
+                        'other names need to have raw device and vlan id ' +
+                        'attributes',
+                'attrs' : {
+                        'vlan-raw-device' :
+                            {'help' : 'vlan raw device'},
+                        'vlan-id' :
+                            {'help' : 'vlan id'}}}
+
+
+    def __init__(self, *args, **kargs):
+        moduleBase.__init__(self, *args, **kargs)
+        self.ipcmd = None
+        self._bridge_vids_query_cache = {}
+        self._resv_vlan_range =  self._get_reserved_vlan_range()
+        self.logger.debug('%s: using reserved vlan range %s'
+                  %(self.__class__.__name__, str(self._resv_vlan_range)))
+
+    def _is_vlan_device(self, ifaceobj):
+        vlan_raw_device = ifaceobj.get_attr_value_first('vlan-raw-device')
+        if vlan_raw_device:
+            return True
+        elif '.' in ifaceobj.name:
+            return True
+        return False
+
+    def _get_vlan_id(self, ifaceobj):
+        """ Derives vlanid from iface name
+        
+        Example:
+            Returns 1 for ifname vlan0001 returns 1
+            Returns 1 for ifname vlan1
+            Returns 1 for ifname eth0.1
+
+            Returns -1 if vlan id cannot be determined
+        """
+        vid_str = ifaceobj.get_attr_value_first('vlan-id')
+        try:
+            if vid_str: return int(vid_str)
+        except:
+            return -1
+
+        if '.' in ifaceobj.name:
+            vid_str = ifaceobj.name.split('.', 1)[1]
+        elif ifaceobj.name.startswith('vlan'):
+            vid_str = ifaceobj.name[4:]
+        else:
+            return -1
+        try:
+            vid = int(vid_str)
+        except:
+            return -1
+        return vid
+
+    def _is_vlan_by_name(self, ifacename):
+        return '.' in ifacename
+
+    def _get_vlan_raw_device_from_ifacename(self, ifacename):
+        """ Returns vlan raw device from ifname
+        Example:
+            Returns eth0 for ifname eth0.100
+
+            Returns None if vlan raw device name cannot
+            be determined
+        """
+        vlist = ifacename.split('.', 1)
+        if len(vlist) == 2:
+            return vlist[0]
+        return None
+
+    def _get_vlan_raw_device(self, ifaceobj):
+        vlan_raw_device = ifaceobj.get_attr_value_first('vlan-raw-device')
+        if vlan_raw_device:
+            return vlan_raw_device
+        return self._get_vlan_raw_device_from_ifacename(ifaceobj.name)
+        
+    def get_dependent_ifacenames(self, ifaceobj, ifaceobjs_all=None):
+        if not self._is_vlan_device(ifaceobj):
+            return None
+        ifaceobj.link_kind |= ifaceLinkKind.VLAN
+        return [self._get_vlan_raw_device(ifaceobj)]
+
+    def _bridge_vid_add_del(self, ifaceobj, bridgename, vlanid,
+                            add=True):
+        """ If the lower device is a vlan aware bridge, add/del the vlanid
+        to the bridge """
+        if self.ipcmd.bridge_is_vlan_aware(bridgename):
+           if add:
+              rtnetlink_api.rtnl_api.bridge_vlan(add=True, dev=bridgename,
+                                                 vid=vlanid, master=False)
+           else:
+              rtnetlink_api.rtnl_api.bridge_vlan(add=False, dev=bridgename,
+                                                 vid=vlanid, master=False)
+
+    def _bridge_vid_check(self, ifaceobj, ifaceobjcurr, bridgename, vlanid):
+        """ If the lower device is a vlan aware bridge, check if the vlanid
+        is configured on the bridge """
+        if not self.ipcmd.bridge_is_vlan_aware(bridgename):
+            return
+        vids = self._bridge_vids_query_cache.get(bridgename)
+        if vids == None:
+           vids = self.ipcmd.bridge_port_vids_get(bridgename)
+           self._bridge_vids_query_cache[bridgename] = vids
+        if not vids or vlanid not in vids:
+            ifaceobjcurr.status = ifaceStatus.ERROR
+            ifaceobjcurr.status_str = 'bridge vid error'
+
+    def _up(self, ifaceobj):
+        vlanid = self._get_vlan_id(ifaceobj)
+        if vlanid == -1:
+            raise Exception('could not determine vlanid')
+        if self._handle_reserved_vlan(vlanid, ifaceobj.name):
+           return
+        vlanrawdevice = self._get_vlan_raw_device(ifaceobj)
+        if not vlanrawdevice:
+            raise Exception('could not determine vlan raw device')
+        if not self.PERFMODE:
+            if not self.ipcmd.link_exists(vlanrawdevice):
+                raise Exception('rawdevice %s not present' %vlanrawdevice)
+            if self.ipcmd.link_exists(ifaceobj.name):
+                self._bridge_vid_add_del(ifaceobj, vlanrawdevice, vlanid)
+                return
+        rtnetlink_api.rtnl_api.create_vlan(vlanrawdevice,
+                    ifaceobj.name, vlanid)
+        self._bridge_vid_add_del(ifaceobj, vlanrawdevice, vlanid)
+        if ifaceobj.addr_method == 'manual':
+           rtnetlink_api.rtnl_api.link_set(ifaceobj.name, "up")
+
+    def _down(self, ifaceobj):
+        vlanid = self._get_vlan_id(ifaceobj)
+        if vlanid == -1:
+            raise Exception('could not determine vlanid')
+        vlanrawdevice = self._get_vlan_raw_device(ifaceobj)
+        if not vlanrawdevice:
+            raise Exception('could not determine vlan raw device')
+        if not self.PERFMODE and not self.ipcmd.link_exists(ifaceobj.name):
+           return
+        try:
+            self.ipcmd.link_delete(ifaceobj.name)
+            self._bridge_vid_add_del(ifaceobj, vlanrawdevice, vlanid, add=False)
+        except Exception, e:
+            self.log_warn(str(e))
+
+    def _query_check(self, ifaceobj, ifaceobjcurr):
+        if not self.ipcmd.link_exists(ifaceobj.name):
+           return
+        if not '.' in ifaceobj.name:
+            # if vlan name is not in the dot format, check its running state
+            (vlanrawdev, vlanid) = self.ipcmd.get_vlandev_attrs(ifaceobj.name)
+            if vlanrawdev != ifaceobj.get_attr_value_first('vlan-raw-device'):
+                ifaceobjcurr.update_config_with_status('vlan-raw-device',
+                        vlanrawdev, 1)
+            else:
+                ifaceobjcurr.update_config_with_status('vlan-raw-device',
+                        vlanrawdev, 0)
+            if vlanid != ifaceobj.get_attr_value_first('vlan-id'):
+                ifaceobjcurr.update_config_with_status('vlan-id', vlanid, 1)
+            else:
+                ifaceobjcurr.update_config_with_status('vlan-id',
+                        vlanid, 0)
+            self._bridge_vid_check(ifaceobj, ifaceobjcurr, vlanrawdev, vlanid)
+
+    def _query_running(self, ifaceobjrunning):
+        if not self.ipcmd.link_exists(ifaceobjrunning.name):
+            return
+        if not self.ipcmd.get_vlandev_attrs(ifaceobjrunning.name):
+            return
+        # If vlan name is not in the dot format, get the
+        # vlan dev and vlan id
+        if not '.' in ifaceobjrunning.name:
+            (vlanrawdev, vlanid) = self.ipcmd.get_vlandev_attrs(ifaceobjrunning.name)
+            ifaceobjrunning.update_config_dict({(k, v) for k, v in
+                                                {'vlan-raw-device' : vlanrawdev,
+                                                 'vlan-id' : vlanid}.items()
+                                                if v})
+
+    _run_ops = {'pre-up' : _up,
+               'post-down' : _down,
+               'query-checkcurr' : _query_check,
+               'query-running' : _query_running}
+
+    def get_ops(self):
+        """ returns list of ops supported by this module """
+        return self._run_ops.keys()
+
+    def _init_command_handlers(self):
+        if not self.ipcmd:
+            self.ipcmd = iproute2(**self.get_flags())
+        
+
+    def run(self, ifaceobj, operation, query_ifaceobj=None, **extra_args):
+        """ run vlan configuration on the interface object passed as argument
+
+        Args:
+            **ifaceobj** (object): iface object
+
+            **operation** (str): any of 'pre-up', 'post-down', 'query-checkcurr',
+                                 'query-running'
+        Kwargs:
+            **query_ifaceobj** (object): query check ifaceobject. This is only
+                valid when op is 'query-checkcurr'. It is an object same as
+                ifaceobj, but contains running attribute values and its config
+                status. The modules can use it to return queried running state
+                of interfaces. status is success if the running state is same
+                as user required state in ifaceobj. error otherwise.
+        """
+        if ifaceobj.type == ifaceType.BRIDGE_VLAN:
+            return
+        op_handler = self._run_ops.get(operation)
+        if not op_handler:
+            return
+        if (operation != 'query-running' and
+                not self._is_vlan_device(ifaceobj)):
+            return
+        self._init_command_handlers()
+        if operation == 'query-checkcurr':
+            op_handler(self, ifaceobj, query_ifaceobj)
+        else:
+            op_handler(self, ifaceobj)
diff --git a/addons/vrrpd.py b/addons/vrrpd.py
new file mode 100644 (file)
index 0000000..9791141
--- /dev/null
@@ -0,0 +1,167 @@
+#!/usr/bin/python
+#
+# Copyright 2014 Cumulus Networks, Inc. All rights reserved.
+# Author: Roopa Prabhu, roopa@cumulusnetworks.com
+#
+
+try:
+    from ipaddr import IPNetwork
+    from sets import Set
+    from ifupdown.iface import *
+    from ifupdownaddons.modulebase import moduleBase
+    from ifupdownaddons.iproute2 import iproute2
+    import os
+    import glob
+    import logging
+    import signal
+    import subprocess
+    import re
+except ImportError, e:
+    raise ImportError (str(e) + "- required module not found")
+
+class vrrpd(moduleBase):
+    """  ifupdown2 addon module to configure vrrpd attributes """
+
+    _modinfo = {'mhelp' : 'ethtool configuration module for interfaces',
+                'attrs': {
+                      'vrrp-id' :
+                            {'help' : 'vrrp instance id',
+                             'example' : ['vrrp-id 1']},
+                      'vrrp-priority' :
+                            {'help': 'set vrrp priority',
+                             'example' : ['vrrp-priority 20']},
+                      'vrrp-virtual-ip' :
+                            {'help': 'set vrrp virtual ip',
+                             'example' : ['vrrp-virtual-ip 10.0.1.254']}}}
+
+    def __init__(self, *args, **kargs):
+        moduleBase.__init__(self, *args, **kargs)
+        self.ipcmd = None
+
+    def _check_if_process_is_running(self, cmdname, cmdline):
+        targetpids = []
+        pidstr = ''
+        try:
+            pidstr = subprocess.check_output(['/bin/pidof',
+                                             '%s' %cmdname]).strip('\n')
+        except:
+            pass
+        if not pidstr:
+           return []
+
+        pids = pidstr.split()
+        if not pids:
+           return targetpids
+        for pid in pids:
+            tmpcmdline = cmdline.replace(' ', '')
+            try:
+                pcmdline = self.read_file_oneline('/proc/%s/cmdline' %pid)
+                pcmdline = re.sub(r'\\(.)', r'\1', pcmdline)
+                self.logger.info('(%s)' %(pcmdline))
+                self.logger.info('(%s)' %(tmpcmdline))
+                self.logger.info('(%d) (%d)' %(len(pcmdline), len(tmpcmdline)))
+                if pcmdline and pcmdline == tmpcmdline:
+                   targetpids.append(pid)
+            except:
+                pass
+        return targetpids
+            
+    def _up(self, ifaceobj):
+        """ up vrrpd -n -D -i $IFACE -v 1 -p 20 10.0.1.254
+            up ifplugd -i $IFACE -b -f -u0 -d1 -I -p -q """
+
+        if (not self.DRYRUN and
+            not os.path.exists('/sys/class/net/%s' %ifaceobj.name)):
+            return
+
+        cmd = ''
+        attrval = ifaceobj.get_attr_value_first('vrrp-id')
+        if attrval:
+            cmd += ' -v %s' %attrval
+        else:
+            return
+        attrval = ifaceobj.get_attr_value_first('vrrp-priority')
+        if attrval:
+            cmd += ' -p %s' %attrval
+        else:
+            self.logger.warn('%s: incomplete vrrp parameters ' %ifaceobj.name,
+                    '(priority not found)')
+        attrval = ifaceobj.get_attr_value_first('vrrp-virtual-ip')
+        if attrval:
+            cmd += ' %s' %attrval
+        else:
+            self.logger.warn('%s: incomplete vrrp arguments ' %ifaceobj.name,
+                    '(virtual ip not found)')
+            return
+        cmd = '/usr/sbin/vrrpd -n -D -i %s %s' %(ifaceobj.name, cmd)
+        self.exec_command(cmd)
+
+        cmd = '/usr/sbin/ifplugd -i %s -b -f -u0 -d1 -I -p -q' %ifaceobj.name
+        if self._check_if_process_is_running('/usr/sbin/ifplugd', cmd):
+           self.logger.info('%s: ifplugd already running' %ifaceobj.name)
+           return
+        self.exec_command(cmd)
+
+    def _kill_pid_from_file(self, pidfilename):
+        if os.path.exists(pidfilename):
+            pid = self.read_file_oneline(pidfilename)
+            if os.path.exists('/proc/%s' %pid):
+               os.kill(int(pid), signal.SIGTERM)
+
+    def _down(self, ifaceobj):
+        """ down ifplugd -k -i $IFACE
+             down kill $(cat /var/run/vrrpd_$IFACE_*.pid) """
+        attrval = ifaceobj.get_attr_value_first('vrrp-id')
+        if not attrval:
+            return
+        try:
+            self.exec_command('/usr/sbin/ifplugd -k -i %s' %ifaceobj.name)
+        except Exception, e:
+            self.logger.debug('%s: ifplugd down error (%s)'
+                              %(ifaceobj.name, str(e)))
+            pass
+
+        for pidfile in glob.glob('/var/run/vrrpd_%s_*.pid' %ifaceobj.name):
+            try:
+                self._kill_pid_from_file(pidfile)
+            except Exception, e:
+                self.logger.debug('%s: vrrpd down error (%s)'
+                                  %(ifaceobj.name, str(e)))
+                pass
+
+    def _query_check(self, ifaceobj, ifaceobjcurr):
+        # XXX
+        return
+
+
+    _run_ops = {'post-up' : _up,
+                'pre-down' : _down}
+
+    def get_ops(self):
+        """ returns list of ops supported by this module """
+        return self._run_ops.keys()
+
+    def run(self, ifaceobj, operation, query_ifaceobj=None, **extra_args):
+        """ run ethtool configuration on the interface object passed as
+            argument
+
+        Args:
+            **ifaceobj** (object): iface object
+
+            **operation** (str): any of 'post-up', 'query-checkcurr',
+                'query-running'
+        Kwargs:
+            **query_ifaceobj** (object): query check ifaceobject. This is only
+                valid when op is 'query-checkcurr'. It is an object same as
+                ifaceobj, but contains running attribute values and its config
+                status. The modules can use it to return queried running state
+                of interfaces. status is success if the running state is same
+                as user required state in ifaceobj. error otherwise.
+        """
+        op_handler = self._run_ops.get(operation)
+        if not op_handler:
+            return
+        if operation == 'query-checkcurr':
+            op_handler(self, ifaceobj, query_ifaceobj)
+        else:
+            op_handler(self, ifaceobj)
diff --git a/addons/vxlan.py b/addons/vxlan.py
new file mode 100644 (file)
index 0000000..a367e99
--- /dev/null
@@ -0,0 +1,167 @@
+#!/usr/bin/python
+
+from ifupdown.iface import *
+from ifupdownaddons.modulebase import moduleBase
+from ifupdownaddons.iproute2 import iproute2
+import ifupdown.rtnetlink_api as rtnetlink_api
+import logging
+from sets import Set
+
+class vxlan(moduleBase):
+    _modinfo = {'mhelp' : 'vxlan module configures vxlan interfaces.',
+                'attrs' : {
+                        'vxlan-id' :
+                            {'help' : 'vxlan id',
+                             'required' : True,
+                             'example': ['vxlan-id 100']},
+                        'vxlan-local-tunnelip' :
+                            {'help' : 'vxlan local tunnel ip',
+                             'example': ['vxlan-local-tunnelip 172.16.20.103']},
+                        'vxlan-svcnodeip' :
+                            {'help' : 'vxlan id',
+                             'example': ['vxlan-svcnodeip 172.16.22.125']},
+                        'vxlan-remoteip' :
+                            {'help' : 'vxlan remote ip',
+                             'example': ['vxlan-remoteip 172.16.22.127']},
+                        'vxlan-learning' :
+                            {'help' : 'vxlan learning on/off',
+                             'example': ['vxlan-learning off'],
+                             'default': 'on'},
+                }}
+
+    def __init__(self, *args, **kargs):
+        moduleBase.__init__(self, *args, **kargs)
+        self.ipcmd = None
+
+    def get_dependent_ifacenames(self, ifaceobj, ifaceobjs_all=None):
+        if not self._is_vxlan_device(ifaceobj):
+            return None
+        ifaceobj.link_kind |= ifaceLinkKind.VXLAN
+        return None
+
+    def _is_vxlan_device(self, ifaceobj):
+        if ifaceobj.get_attr_value_first('vxlan-id'):
+            return True
+        return False
+
+    def _up(self, ifaceobj):
+        vxlanid = ifaceobj.get_attr_value_first('vxlan-id')
+        if vxlanid:
+            self.ipcmd.link_create_vxlan(ifaceobj.name, vxlanid,
+            localtunnelip=ifaceobj.get_attr_value_first('vxlan-local-tunnelip'),
+            svcnodeips=ifaceobj.get_attr_value('vxlan-svcnodeip'),
+            remoteips=ifaceobj.get_attr_value('vxlan-remoteip'),
+            learning=ifaceobj.get_attr_value_first('vxlan-learning'),
+            ageing=ifaceobj.get_attr_value_first('vxlan-ageing'))
+            if ifaceobj.addr_method == 'manual':
+               rtnetlink_api.rtnl_api.link_set(ifaceobj.name, "up")
+
+    def _down(self, ifaceobj):
+        try:
+            self.ipcmd.link_delete(ifaceobj.name)
+        except Exception, e:
+            self.log_warn(str(e))
+
+    def _query_check_n_update(self, ifaceobjcurr, attrname, attrval,
+                              running_attrval):
+        if running_attrval and attrval == running_attrval:
+           ifaceobjcurr.update_config_with_status(attrname, attrval, 0)
+        else:
+           ifaceobjcurr.update_config_with_status(attrname, running_attrval, 1)
+
+    def _query_check_n_update_addresses(self, ifaceobjcurr, attrname,
+                                        addresses, running_addresses):
+        if addresses:
+            for a in addresses: 
+                if a in running_addresses:
+                    ifaceobjcurr.update_config_with_status(attrname, a, 0)
+                else:
+                    ifaceobjcurr.update_config_with_status(attrname, a, 1)
+            running_addresses = Set(running_addresses).difference(
+                                                    Set(addresses))
+        [ifaceobjcurr.update_config_with_status(attrname, a, 1)
+                    for a in running_addresses]
+
+    def _query_check(self, ifaceobj, ifaceobjcurr):
+        if not self.ipcmd.link_exists(ifaceobj.name):
+           return
+        # Update vxlan object
+        vxlanattrs = self.ipcmd.get_vxlandev_attrs(ifaceobj.name)
+        if not vxlanattrs:
+            ifaceobjcurr.check_n_update_config_with_status_many(ifaceobj,
+                    self.get_mod_attrs(), -1)
+            return
+        self._query_check_n_update(ifaceobjcurr, 'vxlan-id',
+                       ifaceobj.get_attr_value_first('vxlan-id'), 
+                       vxlanattrs.get('vxlanid'))
+
+        self._query_check_n_update(ifaceobjcurr, 'vxlan-local-tunnelip',
+                       ifaceobj.get_attr_value_first('vxlan-local-tunnelip'), 
+                       vxlanattrs.get('local'))
+
+        self._query_check_n_update_addresses(ifaceobjcurr, 'vxlan-svcnodeip',
+                       ifaceobj.get_attr_value('vxlan-svcnodeip'), 
+                       vxlanattrs.get('svcnode', []))
+
+        self._query_check_n_update_addresses(ifaceobjcurr, 'vxlan-remoteip',
+                       ifaceobj.get_attr_value('vxlan-remoteip'), 
+                       vxlanattrs.get('remote', []))
+
+        learning = ifaceobj.get_attr_value_first('vxlan-learning')
+        if not learning:
+            learning = 'on'
+        running_learning = vxlanattrs.get('learning')
+        if learning == running_learning:
+           ifaceobjcurr.update_config_with_status('vxlan-learning',
+                                                  running_learning, 0)
+        else:
+           ifaceobjcurr.update_config_with_status('vxlan-learning',
+                                                  running_learning, 1)
+
+    def _query_running(self, ifaceobjrunning):
+        vxlanattrs = self.ipcmd.get_vxlandev_attrs(ifaceobjrunning.name)
+        if not vxlanattrs:
+            return
+        attrval = vxlanattrs.get('vxlanid')
+        if attrval:
+            ifaceobjrunning.update_config('vxlan-id', vxlanattrs.get('vxlanid'))
+        attrval = vxlanattrs.get('local')
+        if attrval:
+            ifaceobjrunning.update_config('vxlan-local-tunnelip', attrval)
+        attrval = vxlanattrs.get('svcnode')
+        if attrval:
+            [ifaceobjrunning.update_config('vxlan-svcnode', a)
+                        for a in attrval]
+        attrval = vxlanattrs.get('remote')
+        if attrval:
+            [ifaceobjrunning.update_config('vxlan-remoteip', a)
+                        for a in attrval]
+        attrval = vxlanattrs.get('learning')
+        if attrval and attrval == 'on':
+            ifaceobjrunning.update_config('vxlan-learning', 'on')
+
+
+    _run_ops = {'pre-up' : _up,
+               'post-down' : _down,
+               'query-checkcurr' : _query_check,
+               'query-running' : _query_running}
+
+    def get_ops(self):
+        return self._run_ops.keys()
+
+    def _init_command_handlers(self):
+        if not self.ipcmd:
+            self.ipcmd = iproute2(**self.get_flags())
+
+    def run(self, ifaceobj, operation, query_ifaceobj=None, **extra_args):
+        op_handler = self._run_ops.get(operation)
+        if not op_handler:
+            return
+        if (operation != 'query-running' and
+                not self._is_vxlan_device(ifaceobj)):
+            return
+        self._init_command_handlers()
+        if operation == 'query-checkcurr':
+            op_handler(self, ifaceobj, query_ifaceobj)
+        else:
+            op_handler(self, ifaceobj)
diff --git a/build.sh b/build.sh
new file mode 100755 (executable)
index 0000000..9fd4f2b
--- /dev/null
+++ b/build.sh
@@ -0,0 +1,8 @@
+#!/bin/bash
+
+TOPDIR=.
+
+${TOPDIR}/scripts/genmanpages.sh ${TOPDIR}/man.rst ${TOPDIR}/man
+
+python setup.py --command-packages=stdeb.command sdist_dsc bdist_deb
+
diff --git a/completion/ifup b/completion/ifup
new file mode 100644 (file)
index 0000000..0be547f
--- /dev/null
@@ -0,0 +1,9 @@
+
+_python_argcomplete() {
+    local IFS='\v'
+    COMPREPLY=( $(IFS="$IFS" COMP_LINE="$COMP_LINE" COMP_POINT="$COMP_POINT"                   _ARGCOMPLETE_COMP_WORDBREAKS="$COMP_WORDBREAKS"                   _ARGCOMPLETE=1  "$1" 8>&1 9>&2 1>/dev/null 2>/dev/null) )
+    if [[ $? != 0 ]]; then
+        unset COMPREPLY
+    fi
+}
+complete -F _python_argcomplete ifup ifdown ifquery ifreload
diff --git a/config/addons.conf b/config/addons.conf
new file mode 100644 (file)
index 0000000..a96b75e
--- /dev/null
@@ -0,0 +1,29 @@
+pre-up,ifenslave
+pre-up,clagd
+pre-up,vlan
+pre-up,vxlan
+pre-up,usercmds
+pre-up,bridge
+pre-up,bridgevlan
+pre-up,mstpctl
+up,dhcp
+up,address
+up,addressvirtual
+up,usercmds
+post-up,ethtool
+post-up,usercmds
+post-up,clagd
+pre-down,usercmds
+pre-down,ethtool
+down,dhcp
+down,addressvirtual
+down,address
+down,usercmds
+post-down,clagd
+post-down,mstpctl
+post-down,bridgevlan
+post-down,bridge
+post-down,vxlan
+post-down,vlan
+post-down,ifenslave
+post-down,usercmds
diff --git a/config/ifupdown2.conf b/config/ifupdown2.conf
new file mode 100644 (file)
index 0000000..82c618e
--- /dev/null
@@ -0,0 +1,44 @@
+#
+# ifupdown2 configuration file
+#
+# This file contains default settings for ifupdown
+#
+
+# default template engine (only mako is currently supported)
+template_engine=mako
+
+# default template lookup path during template rendering
+template_lookuppath=/etc/network/ifupdown2/templates
+
+# Support /etc/network/if-*/ scripts
+addon_scripts_support=0
+
+# By default ifupdown2 only supports a single vlan filtering bridge
+# on the system. Set this flag to 1 to support multiple vlan
+# filtering bridges
+multiple_vlan_aware_bridge_support=0
+
+# ifquery check status strings.
+# By default `ifquery --check` prints the check and
+# cross marks against interface attributes.
+# Use the below strings to modify the default behaviour.
+#
+ifquery_check_success_str=[pass]
+ifquery_check_error_str=[fail]
+ifquery_check_unknown_str=
+#
+
+# This attribute controls iface/vlan range expansions
+# in ifquery default output.
+ifquery_ifacename_expand_range=0
+
+# Let link master (bridges, bonds) own the link state of slaves
+link_master_slave=1
+
+# Delay admin state change till the end
+delay_admin_state_change=0
+
+# ifreload by default downs: 'all interfaces for which config changed' +
+# 'interfaces that were deleted'. With the below variable set to '0'
+# ifreload will only down 'interfaces that were deleted'
+ifreload_down_changed=0
diff --git a/config/networking b/config/networking
new file mode 100644 (file)
index 0000000..cc3d3ef
--- /dev/null
@@ -0,0 +1,23 @@
+#
+#
+# Parameters for the /etc/init.d/networking script
+#
+#
+
+# Change the below to yes if you want verbose logging to be enabled
+VERBOSE="no"
+
+# Change the below to yes if you want debug logging to be enabled
+DEBUG="no"
+
+# Change the below to yes if you want logging to go to syslog
+SYSLOG="no"
+
+# Exclude interfaces
+EXCLUDE_INTERFACES=
+
+# Set to 'yes' if you want to skip ifdown during system reboot
+# and shutdown. This is of interest in large scale interface
+# deployments where you dont want to wait for interface
+# deconfiguration to speed up shutdown/reboot
+SKIP_DOWN_AT_SYSRESET="yes"
diff --git a/debian/copyright b/debian/copyright
new file mode 100644 (file)
index 0000000..f560d80
--- /dev/null
@@ -0,0 +1,30 @@
+Format: http://www.debian.org/doc/packaging-manuals/copyright-format/1.0/
+Upstream-Name: ifupdown2
+Source: http://www.cumulusnetworks.com
+
+Files: *
+Copyright: 2013 Cumulus Networks
+License: GPL-2
+
+Files: debian/*
+Copyright: 2013 Cumulus Networks
+License: GPL-2
+ This package 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; version 2 of the License
+ .
+ This package 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/>
+ .
+ On Debian systems, the complete text of the GNU General
+ Public License version 2 can be found in "/usr/share/common-licenses/GPL-2".
+
+# Please also look if there are files or directories which have a
+# different copyright/license attached and list them here.
+# Please avoid to pick license terms that are more restrictive than the
+# packaged work, as it may make Debian's contributions unacceptable upstream.
diff --git a/debian/python-ifupdown2.postinst b/debian/python-ifupdown2.postinst
new file mode 100644 (file)
index 0000000..cf61919
--- /dev/null
@@ -0,0 +1,114 @@
+#!/bin/sh
+# postinst script for ifupdown2
+#
+# see: dh_installdeb(1)
+
+set -e
+
+# summary of how this script can be called:
+#        * <postinst> `configure' <most-recently-configured-version>
+#        * <old-postinst> `abort-upgrade' <new version>
+#        * <conflictor's-postinst> `abort-remove' `in-favour' <package>
+#          <new-version>
+#        * <postinst> `abort-remove'
+#        * <deconfigured's-postinst> `abort-deconfigure' `in-favour'
+#          <failed-install-package> <version> `removing'
+#          <conflicting-package> <version>
+# for details, see http://www.debian.org/doc/debian-policy/ or
+# the debian-policy package
+
+process_udev()
+{
+    # override default udev bridge and hotplug rules because they interfere with
+    # networking init script
+    udev_user_rulesdir=/etc/udev/rules.d/
+    udev_sys_rulesdir=/lib/udev/rules.d/
+    if [ -e $udev_user_rulesdir ]; then
+        udev_ifupdown2_overrides="80-networking.rules
+        60-bridge-network-interface.rules"
+        for u in ${udev_ifupdown2_overrides}
+        do
+            if [ -e ${udev_sys_rulesdir}/$u -a ! -e ${udev_user_rulesdir}/$u ]; then
+                (cd ${udev_user_rulesdir} && ln -sf /dev/null $u)
+            fi
+        done
+    fi
+}
+
+MYNAME="${0##*/}"
+
+report() { echo "${MYNAME}: $*" ; }
+report_warn() { report "Warning: $*" >&2 ; }
+report_err() { report "Error: $*" >&2 ; }
+
+case "$1" in
+    configure)
+        # Create /etc/network/run
+        [ -d /run/network ] || mkdir -p /run/network
+
+        # for backward compatibility
+        if [ ! -f /etc/network/run ]; then
+            ln -sf /run/network /etc/network/run
+        fi
+
+        ln -sf /usr/share/python-ifupdown2/generate_interfaces.py \
+            /usr/share/doc/python-ifupdown2/examples/generate_interfaces.py
+
+        [ -d /etc/network/if-pre-up.d ] || mkdir -p /etc/network/if-pre-up.d
+        [ -d /etc/network/if-up.d ] || mkdir -p /etc/network/if-up.d
+        [ -d /etc/network/if-post-up.d ] || mkdir -p /etc/network/if-post-up.d
+
+        [ -d /etc/network/if-pre-down.d ] || mkdir -p /etc/network/if-pre-down.d
+        [ -d /etc/network/if-down.d ] || mkdir -p /etc/network/if-down.d
+        [ -d /etc/network/if-post-down.d ] || mkdir -p /etc/network/if-post-down.d
+
+
+        # Generic stuff done on all configurations
+        if [ -f /etc/network/interfaces ] ; then
+            # TODO: This should be handled with debconf and the script
+            # could introduce the line there directly
+            if ! grep -q "^[[:space:]]*iface[[:space:]]\+lo0\?[[:space:]]\+inet[[:space:]]\+loopback\>" /etc/network/interfaces ; then
+                report_warn "No 'iface lo' definition found in /etc/network/interfaces"
+            fi
+
+            if ! grep -q "^[[:space:]]*\(allow-\|\)auto[[:space:]]\+\(.*[[:space:]]\+\|\)lo0\?\([[:space:]]\+\|$\)" /etc/network/interfaces ; then
+                report_warn "No 'auto lo' statement found in /etc/network/interfaces"
+            fi
+        else  # ! -f /etc/network/interfaces
+            if [ -z "$2" ]; then
+                echo "Creating /etc/network/interfaces."
+                echo "# interfaces(5) file used by ifup(8) and ifdown(8)" > /etc/network/interfaces
+                echo "auto lo" >> /etc/network/interfaces
+                    echo "iface lo inet loopback" >> /etc/network/interfaces
+            else
+                    report_warn "/etc/network/interfaces does not exist"
+            fi
+        fi
+
+        [ -e /sbin/ifup ] || ln -sf /sbin/ifupdown /sbin/ifup
+        [ -e /sbin/ifdown ] || ln -sf /sbin/ifupdown /sbin/ifdown
+        [ -e /sbin/ifquery ] || ln -sf /sbin/ifupdown /sbin/ifquery
+        [ -e /sbin/ifreload ] || ln -sf /sbin/ifupdown /sbin/ifreload
+
+        (cd /usr/share/man/man8/ && ln -sf /usr/share/man/man8/ifup.8.gz ifdown.8.gz)
+
+        mkdir -p /etc/network/interfaces.d/
+        process_udev
+        update-rc.d networking start 40 S . start 35 0 6 . >/dev/null
+        ;;
+
+    abort-upgrade|abort-remove|abort-deconfigure)
+        ;;
+
+    *)
+        echo "postinst called with unknown argument \`$1'" >&2
+        exit 1
+        ;;
+esac
+
+# dh_installdeb will replace this with shell code automatically
+# generated by other debhelper scripts.
+
+#DEBHELPER#
+
+exit 0
diff --git a/debian/python-ifupdown2.postrm b/debian/python-ifupdown2.postrm
new file mode 100644 (file)
index 0000000..fe68eb4
--- /dev/null
@@ -0,0 +1,71 @@
+#!/bin/sh
+# postrm script for ifupdown2
+#
+# see: dh_installdeb(1)
+
+set -e
+
+# summary of how this script can be called:
+#        * <postrm> `remove'
+#        * <postrm> `purge'
+#        * <old-postrm> `upgrade' <new-version>
+#        * <new-postrm> `failed-upgrade' <old-version>
+#        * <new-postrm> `abort-install'
+#        * <new-postrm> `abort-install' <old-version>
+#        * <new-postrm> `abort-upgrade' <old-version>
+#        * <disappearer's-postrm> `disappear' <overwriter>
+#          <overwriter-version>
+# for details, see http://www.debian.org/doc/debian-policy/ or
+# the debian-policy package
+
+process_udev()
+{
+    udevlink=$(readlink /etc/udev/rules.d/80-networking.rules 2>/dev/null || true)
+    [ -n "$udevlink" -a "$udevlink" == "/dev/null" ] && rm -f /etc/udev/rules.d/80-networking.rules
+    udevlink=$(readlink /etc/udev/rules.d/60-bridge-network-interface.rules 2>/dev/null || true)
+    [ -n "$udevlink" -a "$udevlink" == "/dev/null" ] && rm -f /etc/udev/rules.d/60-bridge-network-interface.rules
+}
+
+postrm_remove()
+{
+       rm -f /sbin/ifup /sbin/ifdown /sbin/ifquery
+    process_udev
+       update-rc.d networking remove >/dev/null
+}
+
+# Note: We don't remove /etc/network/interfaces
+postrm_purge()
+{
+       rm -f /var/tmp/network/ifstatenew
+       if [ -L /etc/network/run ] ; then
+               rm -f /etc/network/run
+       elif [ -d /etc/network/run ] ; then
+               rmdir --ignore-fail-on-non-empty /etc/network/run
+       fi
+}
+
+case "$1" in
+       purge)
+               postrm_purge
+       ;;
+
+       remove)
+               postrm_remove
+       ;;
+
+
+       upgrade|disappear|failed-upgrade|abort-install|abort-upgrade)
+       ;;
+
+       *)
+               echo "postrm called with unknown argument \`$1'" >&2
+               exit 1
+       ;;
+esac
+
+# dh_installdeb will replace this with shell code automatically
+# generated by other debhelper scripts.
+
+#DEBHELPER#
+
+exit 0
diff --git a/debian/python-ifupdown2.preinst b/debian/python-ifupdown2.preinst
new file mode 100755 (executable)
index 0000000..3fcaed1
--- /dev/null
@@ -0,0 +1,56 @@
+#!/bin/sh
+# preinst script for newpkg
+#
+# see: dh_installdeb(1)
+
+set -e
+
+# summary of how this script can be called:
+#        * <new-preinst> `install'
+#        * <new-preinst> `install' <old-version>
+#        * <new-preinst> `upgrade' <old-version>
+#        * <old-preinst> `abort-upgrade' <new-version>
+# for details, see http://www.debian.org/doc/debian-policy/ or
+# the debian-policy package
+
+preinst_upgrade()
+{
+       local oldver="$1"
+       local udev_user_rulesdir="/etc/udev/rules.d"
+
+       # we have to fixup the filesystem here as previous packages of
+       # ifupdown2 introduced a bug in the postrm script that require
+       # these files to exist, otherwise the postrm script will always
+       # fail.
+       local badver="0.1-cl2.5+2"
+       if dpkg --compare-versions "${oldver}" "lt" "${badver}"; then
+               local files="${udev_user_rulesdir}/80-networking.rules
+                       ${udev_user_rulesdir}/60-bridge-network-interface.rules"
+               for f in ${files}; do
+                       echo "touching udev rule: ${f}"
+                       test ! -e "${f}" && ln -s /dev/null "${f}" || \
+                               /bin/echo -e "\tudev rule exists leaving"
+               done
+       fi
+}
+
+case "$1" in
+       install|upgrade)
+               preinst_upgrade "$2"
+       ;;
+
+       abort-upgrade)
+       ;;
+
+       *)
+               echo "preinst called with unknown argument \`$1'" >&2
+               exit 1
+       ;;
+esac
+
+# dh_installdeb will replace this with shell code automatically
+# generated by other debhelper scripts.
+
+#DEBHELPER#
+
+exit 0
diff --git a/docs/Makefile b/docs/Makefile
new file mode 100644 (file)
index 0000000..9b5efd7
--- /dev/null
@@ -0,0 +1,153 @@
+# Makefile for Sphinx documentation
+#
+
+# You can set these variables from the command line.
+SPHINXOPTS    =
+SPHINXBUILD   = sphinx-build
+PAPER         =
+BUILDDIR      = build
+
+# Internal variables.
+PAPEROPT_a4     = -D latex_paper_size=a4
+PAPEROPT_letter = -D latex_paper_size=letter
+ALLSPHINXOPTS   = -d $(BUILDDIR)/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) source
+# the i18n builder cannot share the environment and doctrees with the others
+I18NSPHINXOPTS  = $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) source
+
+.PHONY: help clean html dirhtml singlehtml pickle json htmlhelp qthelp devhelp epub latex latexpdf text man changes linkcheck doctest gettext
+
+help:
+       @echo "Please use \`make <target>' where <target> is one of"
+       @echo "  html       to make standalone HTML files"
+       @echo "  dirhtml    to make HTML files named index.html in directories"
+       @echo "  singlehtml to make a single large HTML file"
+       @echo "  pickle     to make pickle files"
+       @echo "  json       to make JSON files"
+       @echo "  htmlhelp   to make HTML files and a HTML help project"
+       @echo "  qthelp     to make HTML files and a qthelp project"
+       @echo "  devhelp    to make HTML files and a Devhelp project"
+       @echo "  epub       to make an epub"
+       @echo "  latex      to make LaTeX files, you can set PAPER=a4 or PAPER=letter"
+       @echo "  latexpdf   to make LaTeX files and run them through pdflatex"
+       @echo "  text       to make text files"
+       @echo "  man        to make manual pages"
+       @echo "  texinfo    to make Texinfo files"
+       @echo "  info       to make Texinfo files and run them through makeinfo"
+       @echo "  gettext    to make PO message catalogs"
+       @echo "  changes    to make an overview of all changed/added/deprecated items"
+       @echo "  linkcheck  to check all external links for integrity"
+       @echo "  doctest    to run all doctests embedded in the documentation (if enabled)"
+
+clean:
+       -rm -rf $(BUILDDIR)/*
+
+html:
+       $(SPHINXBUILD) -b html $(ALLSPHINXOPTS) $(BUILDDIR)/html
+       @echo
+       @echo "Build finished. The HTML pages are in $(BUILDDIR)/html."
+
+dirhtml:
+       $(SPHINXBUILD) -b dirhtml $(ALLSPHINXOPTS) $(BUILDDIR)/dirhtml
+       @echo
+       @echo "Build finished. The HTML pages are in $(BUILDDIR)/dirhtml."
+
+singlehtml:
+       $(SPHINXBUILD) -b singlehtml $(ALLSPHINXOPTS) $(BUILDDIR)/singlehtml
+       @echo
+       @echo "Build finished. The HTML page is in $(BUILDDIR)/singlehtml."
+
+pickle:
+       $(SPHINXBUILD) -b pickle $(ALLSPHINXOPTS) $(BUILDDIR)/pickle
+       @echo
+       @echo "Build finished; now you can process the pickle files."
+
+json:
+       $(SPHINXBUILD) -b json $(ALLSPHINXOPTS) $(BUILDDIR)/json
+       @echo
+       @echo "Build finished; now you can process the JSON files."
+
+htmlhelp:
+       $(SPHINXBUILD) -b htmlhelp $(ALLSPHINXOPTS) $(BUILDDIR)/htmlhelp
+       @echo
+       @echo "Build finished; now you can run HTML Help Workshop with the" \
+             ".hhp project file in $(BUILDDIR)/htmlhelp."
+
+qthelp:
+       $(SPHINXBUILD) -b qthelp $(ALLSPHINXOPTS) $(BUILDDIR)/qthelp
+       @echo
+       @echo "Build finished; now you can run "qcollectiongenerator" with the" \
+             ".qhcp project file in $(BUILDDIR)/qthelp, like this:"
+       @echo "# qcollectiongenerator $(BUILDDIR)/qthelp/ifupdown2.qhcp"
+       @echo "To view the help file:"
+       @echo "# assistant -collectionFile $(BUILDDIR)/qthelp/ifupdown2.qhc"
+
+devhelp:
+       $(SPHINXBUILD) -b devhelp $(ALLSPHINXOPTS) $(BUILDDIR)/devhelp
+       @echo
+       @echo "Build finished."
+       @echo "To view the help file:"
+       @echo "# mkdir -p $$HOME/.local/share/devhelp/ifupdown2"
+       @echo "# ln -s $(BUILDDIR)/devhelp $$HOME/.local/share/devhelp/ifupdown2"
+       @echo "# devhelp"
+
+epub:
+       $(SPHINXBUILD) -b epub $(ALLSPHINXOPTS) $(BUILDDIR)/epub
+       @echo
+       @echo "Build finished. The epub file is in $(BUILDDIR)/epub."
+
+latex:
+       $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex
+       @echo
+       @echo "Build finished; the LaTeX files are in $(BUILDDIR)/latex."
+       @echo "Run \`make' in that directory to run these through (pdf)latex" \
+             "(use \`make latexpdf' here to do that automatically)."
+
+latexpdf:
+       $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex
+       @echo "Running LaTeX files through pdflatex..."
+       $(MAKE) -C $(BUILDDIR)/latex all-pdf
+       @echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex."
+
+text:
+       $(SPHINXBUILD) -b text $(ALLSPHINXOPTS) $(BUILDDIR)/text
+       @echo
+       @echo "Build finished. The text files are in $(BUILDDIR)/text."
+
+man:
+       $(SPHINXBUILD) -b man $(ALLSPHINXOPTS) $(BUILDDIR)/man
+       @echo
+       @echo "Build finished. The manual pages are in $(BUILDDIR)/man."
+
+texinfo:
+       $(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo
+       @echo
+       @echo "Build finished. The Texinfo files are in $(BUILDDIR)/texinfo."
+       @echo "Run \`make' in that directory to run these through makeinfo" \
+             "(use \`make info' here to do that automatically)."
+
+info:
+       $(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo
+       @echo "Running Texinfo files through makeinfo..."
+       make -C $(BUILDDIR)/texinfo info
+       @echo "makeinfo finished; the Info files are in $(BUILDDIR)/texinfo."
+
+gettext:
+       $(SPHINXBUILD) -b gettext $(I18NSPHINXOPTS) $(BUILDDIR)/locale
+       @echo
+       @echo "Build finished. The message catalogs are in $(BUILDDIR)/locale."
+
+changes:
+       $(SPHINXBUILD) -b changes $(ALLSPHINXOPTS) $(BUILDDIR)/changes
+       @echo
+       @echo "The overview file is in $(BUILDDIR)/changes."
+
+linkcheck:
+       $(SPHINXBUILD) -b linkcheck $(ALLSPHINXOPTS) $(BUILDDIR)/linkcheck
+       @echo
+       @echo "Link check complete; look for any errors in the above output " \
+             "or in $(BUILDDIR)/linkcheck/output.txt."
+
+doctest:
+       $(SPHINXBUILD) -b doctest $(ALLSPHINXOPTS) $(BUILDDIR)/doctest
+       @echo "Testing of doctests in the sources finished, look at the " \
+             "results in $(BUILDDIR)/doctest/output.txt."
diff --git a/docs/examples/generate_interfaces.py b/docs/examples/generate_interfaces.py
new file mode 100755 (executable)
index 0000000..bfb2d88
--- /dev/null
@@ -0,0 +1,150 @@
+#!/usr/bin/python
+
+import argparse
+import sys
+import subprocess
+
+""" This script prints to stdout /etc/network/interfaces entries for
+    requested interfaces.
+
+    Currently it supports generation of interfaces(5) section for all
+    swp interfaces on the system. And also an interface section 
+    for a bridge with all swp ports.
+
+    Example use of this script:
+
+    generate the swp_defaults file:
+    (bkup existing /etc/network/interfaces.d/swp_defaults file if one exists)
+
+    #generate_interfaces.py -s > /etc/network/interfaces.d/swp_defaults
+
+    User -m option if you want the new swp_defaults to be auto merged
+    with the contents from the old file, use -m option
+
+    #generate_interfaces.py -s -m /etc/network/interfaces.d/swp_defaults > /etc/network/interfaces.d/swp_defaults.new
+
+    Include the swp_defaults file in /etc/network/interfaces file
+    (if not already there) using the source command as shown below:
+
+    source /etc/network/interfaces.d/swp_defaults
+
+"""
+
+def get_swp_interfaces():
+    porttab_path = '/var/lib/cumulus/porttab'
+    ports = []
+
+    ptfile = open(porttab_path, 'r')
+    for line in ptfile.readlines():
+        line = line.strip()
+        if '#' in line:
+            continue
+        try:
+            ports.append(line.split()[0])
+        except ValueError:
+            continue
+    return ports
+
+def print_swp_defaults_header():
+    print '''
+# ** This file is autogenerated by /usr/share/doc/python-ifupdown2/generate_interfaces.py **
+#
+# This is /etc/network/interfaces section for all available swp
+# ports on the system.
+#
+# To include this file in the main /etc/network/interfaces file,
+# copy this file under /etc/network/interfaces.d/ and use the
+# source line in the /etc/network/interfaces file.
+#
+# example entry in /etc/network/interfaces:
+#   source /etc/network/interfaces.d/<filename>
+#
+# See manpage interfaces(5) for details.
+'''
+
+def print_bridge_untagged_defaults_header():
+    print '''
+# ** This file is autogenerated by /usr/share/doc/python-ifupdown2/generate_interfaces.py **
+#
+# This is /etc/network/interfaces section for a bridge device with all swp
+# ports in the system.
+#
+# To include this file in the main /etc/network/interfaces file,
+# copy this file under /etc/network/interfaces.d/ and use the
+# source line in the /etc/network/interfaces file as shown below.
+# details.
+#
+# example entry in /etc/network/interfaces:
+#   source /etc/network/interfaces.d/filename
+#
+# See manpage interfaces(5) for details
+'''
+
+def interfaces_print_swp_default(swp_intf):
+    outbuf = None
+    if args.mergefile:
+        try:
+            cmd = ['/sbin/ifquery', '%s' %swp_intf, '-i', '%s' %args.mergefile]
+            outbuf = subprocess.check_output(cmd, stderr=subprocess.STDOUT)
+        except Exception, e:
+            # no interface found gen latest
+            pass
+    if not outbuf:
+        outbuf = 'auto %s\niface %s\n\n' %(swp_intf, swp_intf)
+    return outbuf
+
+def interfaces_print_swp_defaults(swp_intfs):
+    print_swp_defaults_header()
+    outbuf = ''
+    for i in swp_intfs:
+        outbuf += interfaces_print_swp_default(i)
+    print outbuf
+
+def interfaces_print_bridge_default(swp_intfs):
+    print_bridge_untagged_defaults_header()
+    outbuf = 'auto bridge-untagged\n' 
+    outbuf += 'iface bridge-untagged\n'
+    outbuf += '  bridge-ports \\\n'
+    linen = 5
+    ports = ''
+    for i in range(0, len(swp_intfs), linen):
+        if ports:
+            ports += ' \\\n'
+        ports += '      %s' %(' '.join(swp_intfs[i:i+linen]))
+    outbuf += ports
+    print outbuf
+
+def populate_argparser(argparser):
+    group = argparser.add_mutually_exclusive_group(required=False)
+    group.add_argument('-s', '--swp-defaults', action='store_true',
+                       dest='swpdefaults', help='generate swp defaults file')
+    group.add_argument('-b', '--bridge-default', action='store_true',
+                       dest='bridgedefault',
+                       help='generate default untagged bridge')
+    argparser.add_argument('-m', '--merge', dest='mergefile', help='merge ' +
+                           'new generated iface content with the old one')
+
+argparser =  argparse.ArgumentParser(description='ifupdown interfaces file gen helper')
+populate_argparser(argparser)
+args = argparser.parse_args(sys.argv[1:])
+
+if not args.swpdefaults and not args.bridgedefault:
+    argparser.print_help()
+    exit(1)
+
+if args.bridgedefault and args.mergefile:
+    print 'error: mergefile option currently only supported with -s'
+    argparser.print_help()
+    exit(1)
+
+swp_intfs = get_swp_interfaces()
+if not swp_intfs:
+    print 'error: no ports found'
+    exit(1)
+
+if args.swpdefaults:
+    interfaces_print_swp_defaults(swp_intfs)
+elif args.bridgedefault:
+    interfaces_print_bridge_default(swp_intfs)
+else:
+    argparser.print_help()
diff --git a/docs/examples/interfaces b/docs/examples/interfaces
new file mode 100644 (file)
index 0000000..df05fc1
--- /dev/null
@@ -0,0 +1,74 @@
+# This file describes the network interfaces available on your system
+# and how to activate them. For more information, see interfaces(5).
+
+# The loopback network interface
+auto lo
+iface lo inet loopback
+
+# The primary network interface
+auto eth0
+iface eth0 inet dhcp
+
+#source /etc/network/interfaces.d/template.bridges
+
+# swp interface
+auto swp30
+iface swp30
+    address 12.0.0.4/24
+    address 12.0.0.6/24
+    address 2000:1000:1000:1000:3::5/128
+    mtu 1600
+    alias "test network"
+    link-duplex full
+    link-speed 1000
+    link-autoneg off
+
+# bond interface
+auto bond3
+iface bond3 inet static
+    address 100.0.0.4/16
+    bond-slaves swp1 swp2
+    bond-mode 802.3ad
+    bond-miimon 100
+    bond-use-carrier 1
+    bond-lacp-rate 1
+    bond-min-links 1
+    bond-xmit_hash_policy layer3+4
+
+# bond interface
+auto bond4
+iface bond4 inet static
+    address 100.0.0.6/16
+    bond-slaves swp3 swp4
+    bond-mode 802.3ad
+    bond-miimon 100
+    bond-use-carrier 1
+    bond-lacp-rate 1
+    bond-min-links 1
+    bond-xmit_hash_policy layer3+4
+
+# bond interface
+auto br0
+iface br0
+    address 12.0.0.4/24
+    address 12.0.0.6/24
+    address 2000:1000:1000:1000:3::5/128
+    bridge-ports bond3 bond4 swp5 swp8
+    bridge-stp on
+
+# vlan interface on bond
+auto bond3.2000
+iface bond3.2000 inet static
+    address 100.1.0.4/16
+
+auto bond4.2000
+iface bond4.2000 inet static
+    address 100.1.0.6/16
+
+auto br2000
+iface br2000 inet6 static
+    address 2001:dad:beef::4/64
+    bridge-ports bond3.2000 bond4.2000 swp5.2000
+    bridge-stp on
+    mstpctl-treeprio 61440
+    mstpctl-portp2p bond3.2000=yes bond4.2000=yes
diff --git a/docs/examples/interfaces_bridge_igmp_mstp b/docs/examples/interfaces_bridge_igmp_mstp
new file mode 100644 (file)
index 0000000..f4916f4
--- /dev/null
@@ -0,0 +1,48 @@
+
+#
+# This example lists all attributes for bridge configuration.
+# The attributes with mstpctl- prefix indicate mstp settings on a bridge.
+# The attributes with bridge- prefix indicate bridge stp and igmp attributes.
+# Except bridge-ports, none of the other attributes are required. Default
+# values are documented in the ifupdown-addons-interfaces(5) man page.
+#
+# The bridge in the example below is a vlan unaware bridge (classic linux
+# bridge)
+#
+auto br-300
+iface br-300 inet static
+           address 12.0.0.3/24
+           bridge-ports swp13.300 swp14.300
+           bridge-stp on
+           mstpctl-maxage 20
+           mstpctl-fdelay 15
+           mstpctl-maxhops 20
+           mstpctl-txholdcount 6
+           mstpctl-forcevers rstp
+           mstpctl-portpathcost swp13.300=0 swp14.300=0
+           mstpctl-portadminedge swp13.300=no swp14.300=no
+           mstpctl-portautoedge swp13.300=yes swp14.300=yes
+           mstpctl-portp2p swp13.300=no swp13.300=no
+           mstpctl-portrestrrole swp13.300=no swp14.300=no
+           mstpctl-bpduguard swp13.300=no swp14.300=no
+           mstpctl-portrestrtcn swp13.300=no swp14.300=no
+           mstpctl-treeprio 32768
+           mstpctl-treeportprio swp13.300=128
+           mstpctl-hello 2
+           mstpctl-portnetwork swp13.300=no
+           bridge-mclmc 3
+           bridge-mcrouter 0
+           bridge-mcsnoop  1
+           bridge-mcsqc    3
+           bridge-mcqifaddr 1
+           bridge-mcquerier 1
+           bridge-hashel 3
+           bridge-hashmax 4
+           bridge-mclmi 3
+           bridge-mcmi 200
+           bridge-mcqpi 200
+           bridge-mcqi  100
+           bridge-mcqri 20
+           bridge-mcsqi 50
+           bridge-portmcrouter swp13.300=0
+           bridge-portmcfl     swp13.300=1
diff --git a/docs/examples/interfaces_bridge_template_func b/docs/examples/interfaces_bridge_template_func
new file mode 100644 (file)
index 0000000..61003d6
--- /dev/null
@@ -0,0 +1,33 @@
+#
+# mako template function to create a bridge
+#
+# mako defs provide the advantage of declaring predefined functions in
+# separate files.
+#
+# Below is an example that illustrates how to define such functions and use
+# them in the /etc/network/interfaces file to create bridges
+#
+# This file defines a function makebr to create a bridge. The arguments to the
+# function are vlan and ip address of the bridge.
+#
+# The default directory for template functions is
+# /etc/network/ifupdown2/templates/. Copy this file under the template
+# dir (create the directory if does not exist)
+#
+# To use this template function in /etc/network/interfaces, add the following
+# to the /etc/network/interfaces file:
+#
+# <%namespace name="bridge" file="/bridge_template"/>
+#
+# ${bridge.makebr(1096, "10.0.23.2/24")}
+# ${bridge.makebr(1097, "10.0.23.3/24")}
+#
+#
+
+<%def name="makebr(vlan, addr)">
+auto br${vlan}
+iface br${vlan} inet static
+    address ${addr}
+    bridge-ports swp1.${vlan} swp2.${vlan}
+    bridge-stp on
+</%def>
diff --git a/docs/examples/interfaces_with_template b/docs/examples/interfaces_with_template
new file mode 100644 (file)
index 0000000..af9d571
--- /dev/null
@@ -0,0 +1,24 @@
+#
+# Example interfaces file using mako templates
+#
+# The below section can be copied into
+# /etc/network/interfaces file 
+# or
+# to a file under /etc/network/interfaces.d/
+# and include in the interfaces file using the
+# 'source' command.
+#
+# see manpage interfaces(5) for details
+# 
+#
+
+%for v in range(1000,1100):
+auto vlan-${v}
+iface vlan-${v} inet static
+    bridge-ports glob swp1-6.${v}
+    bridge-stp on
+    bridge-ageing 200
+    bridge-maxage 10
+    bridge-fd 10
+%endfor
+
diff --git a/docs/examples/vlan_aware_bridges/interfaces.basic b/docs/examples/vlan_aware_bridges/interfaces.basic
new file mode 100644 (file)
index 0000000..7506175
--- /dev/null
@@ -0,0 +1,25 @@
+#
+# vlan-aware bridge simple example
+#
+# 'bridge' is a vlan aware bridge with all ports (swp1-52).
+# native vlan is by default 1
+#
+# 'bridge-vids' attribute is used to declare vlans.
+# 'bridge-pvid' attribute is used to specify native vlans if other than 1
+# 'bridge-access' attribute is used to declare access port
+# 
+
+#
+# ports swp1-swp52 are trunk ports which inherit vlans from 'bridge'
+# ie vlans 310 700 707 712 850 910
+      
+#
+# the following is a vlan aware bridge with ports swp1-swp52
+# It has stp on
+#
+auto bridge
+iface bridge
+      bridge-vlan-aware yes
+      bridge-ports glob swp1-52
+      bridge-stp on
+      bridge-vids 310 700 707 712 850 910
diff --git a/docs/examples/vlan_aware_bridges/interfaces.vlan_prune_and_access_ports b/docs/examples/vlan_aware_bridges/interfaces.vlan_prune_and_access_ports
new file mode 100644 (file)
index 0000000..9641a82
--- /dev/null
@@ -0,0 +1,59 @@
+#
+# vlan-aware bridge access ports and pruned vlan example
+#
+# 'bridge' is a vlan aware bridge with all ports (swp1-52).
+# native vlan is by default 1
+#
+# 'bridge-vids' attribute is used to declare vlans.
+# 'bridge-pvid' attribute is used to specify native vlans if other than 1
+# 'bridge-access' attribute is used to declare access port
+#
+# 
+
+# The following is an access port to vlan 310, no trunking
+auto swp1
+iface swp1
+      bridge-access 310
+      mstpctl-portadminedge yes
+      mstpctl-bpduguard yes
+
+# The following is a truk port that is "pruned".
+# native vlan is 1, but only .1q tags of 707, 712, 850 are
+# sent and received
+#
+auto swp2
+iface swp2
+      bridge-vids 707 712 850
+      mstpctl-portadminedge yes
+      mstpctl-bpduguard yes
+     
+# The following port is the trunk uplink and inherits all vlans
+# from 'bridge'
+auto swp49
+iface swp49
+      mstpctl-portpathcost 10
+      # Enable bridge assurance on uplink port using 'portnetwork' attribute
+      mstpctl-portnetwork yes
+
+# The following port is the trunk uplink and inherits all vlans
+# from 'bridge'
+auto swp50
+iface swp50
+      mstpctl-portpathcost 0
+      # Enable bridge assurance on uplink port using 'portnetwork' attribute
+      mstpctl-portnetwork yes
+
+#
+# ports swp3-swp48 are trunk ports which inherit vlans from the 'bridge'
+# ie vlans 310,700,707,712,850,910
+      
+#
+# the following is a vlan aware bridge with ports swp1-swp52
+# It has stp on
+#
+auto bridge
+iface bridge
+      bridge-vlan-aware yes
+      bridge-ports glob swp1-52
+      bridge-stp on
+      bridge-vids 310 700 707 712 850 910
diff --git a/docs/examples/vlan_aware_bridges/interfaces.with_bonds b/docs/examples/vlan_aware_bridges/interfaces.with_bonds
new file mode 100644 (file)
index 0000000..f3425dd
--- /dev/null
@@ -0,0 +1,92 @@
+#
+# vlan-aware bridge with bonds example
+#
+# uplink1, peerlink and downlink are bond interfaces.
+# 'bridge' is a vlan aware bridge with ports uplink1, peerlink
+# and downlink (swp2-20).
+# 
+# native vlan is by default 1
+#
+# 'bridge-vids' attribute is used to declare vlans.
+# 'bridge-pvid' attribute is used to specify native vlans if other than 1
+# 'bridge-access' attribute is used to declare access port
+# 
+auto lo
+iface lo
+
+auto eth0
+iface eth0 inet dhcp
+
+# bond interface
+auto uplink1
+iface uplink1
+    bond-slaves swp32
+    bond-mode 802.3ad
+    bond-miimon 100
+    bond-use-carrier 1
+    bond-lacp-rate 1
+    bond-min-links 1
+    bond-xmit-hash-policy layer2
+    bridge-vids 2000-2079
+
+# bond interface
+auto peerlink
+iface peerlink
+    bond-slaves swp30 swp31
+    bond-mode 802.3ad
+    bond-miimon 100
+    bond-use-carrier 1
+    bond-lacp-rate 1
+    bond-min-links 1
+    bond-xmit-hash-policy layer3+4
+    bridge-vids 2000-2079 4094
+
+# bond interface
+auto downlink
+iface downlink
+    bond-slaves swp1
+    bond-mode 802.3ad
+    bond-miimon 100
+    bond-use-carrier 1
+    bond-lacp-rate 1
+    bond-min-links 1
+    bond-xmit-hash-policy layer3+4
+    bridge-vids 2000-2079
+
+#
+# Declare vlans for all swp ports
+# swp2-20 get vlans from 2004 to 2022.
+# The below uses mako templates to generate iface sections
+# with vlans for swp ports
+#
+%for port, vlanid in zip(range(2, 20), range(2004, 2022)) :
+    auto swp${port}
+    iface swp${port}
+        bridge-vids ${vlanid}
+
+%endfor
+
+# svi vlan 4094
+auto bridge.4094
+iface bridge.4094
+    address 11.100.1.252/24
+
+# l2 attributes for vlan 4094
+auto bridge.4094
+vlan bridge.4094
+    bridge-igmp-querier-src 172.16.101.1
+
+#
+# vlan aware bridge
+#
+auto bridge
+iface bridge
+    bridge-vlan-aware yes
+    bridge-ports uplink1 peerlink downlink glob swp2-20
+    bridge-stp on
+
+# svi peerlink vlan
+auto peerlink.4094
+iface peerlink.4094
+    address 192.168.10.1/30
+    broadcast 192.168.10.3
diff --git a/docs/examples/vlan_aware_bridges/interfaces.with_clag b/docs/examples/vlan_aware_bridges/interfaces.with_clag
new file mode 100644 (file)
index 0000000..8cdccc9
--- /dev/null
@@ -0,0 +1,87 @@
+#
+# vlan-aware bridge with clag example
+#
+#
+# 'bridge' is a vlan aware bridge with ports:
+#      'peer-bond spine-bond glob host-bond-0[1-2]'
+#
+# All ports inherit 'vlans 10 20-23' from the 'bridge-vids' attribute
+# under the bridge
+# 
+# native vlan is by default 1
+#
+# 'bridge-vids' attribute is used to declare vlans.
+# 'bridge-pvid' attribute is used to specify native vlans if other than 1
+# 'bridge-access' attribute is used to declare access port
+# 
+# 'spine-bond host-bond-0[1-2]' are clag bonds and will be considered by
+# clagd for dual connection. clag-id has to be a non-zero and has to match
+# across the peer switches for the bonds to become dual connected.
+
+# spine bond
+#
+auto spine-bond
+iface spine-bond
+      bond-slaves glob swp19-22
+      bond-mode 802.3ad
+      bond-miimon 100
+      bond-use-carrier 1
+      bond-lacp-rate 1
+      bond-min-links 1
+      bond-xmit-hash-policy layer3+4
+      clag-id 100
+
+# mlag bond and peer interface
+#
+auto peer-bond
+iface peer-bond
+      bond-slaves glob swp23-24
+      bond-mode 802.3ad
+      bond-miimon 100
+      bond-use-carrier 1
+      bond-lacp-rate 1
+      bond-min-links 1
+      bond-xmit-hash-policy layer3+4
+
+# sub-interface for clagd communication
+#
+auto peer-bond.4094
+iface peer-bond.4094
+      address 169.254.0.1/30
+      clagd-peer-ip 169.254.0.2
+      clagd-sys-mac 44:38:39:ff:00:01
+      #clagd-priority 4096
+      # Please see man clagd for more options
+      # clagd-args --peerTimeout 30
+
+# host ports
+#
+auto host-bond-01
+iface host-bond-01
+      bond-slaves swp1
+      bond-mode 802.3ad
+      bond-miimon 100
+      bond-use-carrier 1
+      bond-lacp-rate 1
+      bond-min-links 1
+      bond-xmit-hash-policy layer3+4
+      clag-id 1
+
+auto host-bond-02
+iface host-bond-02
+      bond-slaves swp2
+      bond-mode 802.3ad
+      bond-miimon 100
+      bond-use-carrier 1
+      bond-lacp-rate 1
+      bond-min-links 1
+      bond-xmit-hash-policy layer3+4
+      clag-id 2
+
+# the bridge
+auto bridge
+iface bridge
+      bridge-vlan-aware yes
+      bridge-ports peer-bond spine-bond glob host-bond-0[1-2]
+      bridge-stp on
+      bridge-vids 10 20-23
diff --git a/docs/source/addonsapiref.rst b/docs/source/addonsapiref.rst
new file mode 100644 (file)
index 0000000..0954d27
--- /dev/null
@@ -0,0 +1,61 @@
+Documentation for the ifupdownaddons default addons modules
+***********************************************************
+
+address
+=======
+
+.. automodule:: address
+
+.. autoclass:: address
+   :members: run, get_ops
+
+
+bridge
+======
+
+.. automodule:: bridge
+
+.. autoclass:: bridge
+   :members: run, get_ops
+
+dhcp
+====
+
+.. automodule:: dhcp
+
+.. autoclass:: dhcp
+
+ethtool
+=======
+
+.. automodule:: ethtool
+
+.. autoclass:: ethtool
+
+ifenslave
+=========
+
+.. automodule:: ifenslave
+
+.. autoclass:: ifenslave
+
+mstpctl
+=======
+
+.. automodule:: mstpctl
+
+.. autoclass:: mstpctl
+
+usercmds
+========
+
+.. automodule:: usercmds
+
+.. autoclass:: usercmds
+
+vlan
+====
+
+.. automodule:: vlan
+
+.. autoclass:: vlan
diff --git a/docs/source/addonshelperapiref.rst b/docs/source/addonshelperapiref.rst
new file mode 100644 (file)
index 0000000..01d9a41
--- /dev/null
@@ -0,0 +1,44 @@
+Documentation for the ifupdownaddons package helper modules
+***********************************************************
+
+This package contains modules that provide helper methods
+for ifupdown2 addon modules to interact directly with tools
+like iproute2, brctl etc.
+
+
+bridgeutils
+===========
+
+Helper module to work with bridgeutil commands
+
+.. automodule:: bridgeutils
+
+.. autoclass:: brctl
+
+ifenslaveutil
+=============
+
+Helper module to interact with linux api to create bonds.
+Currently this is via sysfs.
+
+.. automodule:: ifenslaveutil
+
+.. autoclass:: ifenslaveutil
+
+dhclient
+========
+
+Helper module to interact with dhclient tools.
+
+.. automodule:: dhclient
+
+.. autoclass:: dhclient
+
+iproute2
+========
+
+Helper module to interact with iproute2 tools.
+
+.. automodule:: iproute2
+
+.. autoclass:: iproute2
diff --git a/docs/source/apiref.rst b/docs/source/apiref.rst
new file mode 100644 (file)
index 0000000..f30dc39
--- /dev/null
@@ -0,0 +1,65 @@
+Documentation for the Code
+**************************
+
+
+ifupdownmain
+============
+
+ifupdownmain is the main ifupdown module.
+
+.. automodule:: ifupdownmain
+
+.. autoclass:: ifupdownMain
+   :members: up, down, reload, query
+
+iface
+=====
+
+.. automodule:: iface
+
+.. autoclass:: iface
+   :members: state, status, flags, priv_flags, refcnt, lowerifaces, upperifaces, add_to_upperifaces, get_attr_value, get_attr_value_first, get_attr_value_n, update_config, update_config_with_status, get_config_attr_status, compare, dump_raw, dump, dump_pretty
+
+.. autoclass:: ifaceState
+
+.. autoclass:: ifaceStatus
+
+.. autoclass:: ifaceJsonEncoder
+
+scheduler
+=========
+
+.. automodule:: scheduler
+
+.. autoclass:: ifaceScheduler
+   :members: sched_ifaces
+
+.. autoclass:: ifaceSchedulerFlags
+
+
+networkinterfaces
+=================
+
+.. automodule:: networkinterfaces
+
+.. autoclass:: networkInterfaces
+   :members: load, subscribe
+
+statemanager
+============
+
+.. automodule:: statemanager
+
+.. autoclass:: pickling
+   :members: save, save_obj, load
+
+.. autoclass:: stateManager
+   :members: read_saved_state, save_state
+
+graph
+=====
+
+.. automodule:: graph
+
+.. autoclass:: graph
+   :members: topological_sort_graphs_all, generate_dots
diff --git a/docs/source/conf.py b/docs/source/conf.py
new file mode 100644 (file)
index 0000000..01bc5cc
--- /dev/null
@@ -0,0 +1,250 @@
+# -*- coding: utf-8 -*-
+#
+# ifupdown2 documentation build configuration file, created by
+# sphinx-quickstart on Sun Jul  6 23:49:20 2014.
+#
+# This file is execfile()d with the current directory set to its containing dir.
+#
+# Note that not all possible configuration values are present in this
+# autogenerated file.
+#
+# All configuration values have a default; values that are commented out
+# serve to show the default.
+
+import sys, os
+
+# If extensions (or modules to document with autodoc) are in another directory,
+# add these directories to sys.path here. If the directory is relative to the
+# documentation root, use os.path.abspath to make it absolute, like shown here.
+sys.path.insert(0, os.path.abspath('../../ifupdown'))
+sys.path.append(os.path.abspath('../../addons'))
+sys.path.append(os.path.abspath('../../'))
+sys.path.append(os.path.abspath('../../ifupdownaddons'))
+sys.path.append(os.path.abspath('../../../ifupdown2'))
+
+# -- General configuration -----------------------------------------------------
+
+# If your documentation needs a minimal Sphinx version, state it here.
+#needs_sphinx = '1.0'
+
+# Add any Sphinx extension module names here, as strings. They can be extensions
+# coming with Sphinx (named 'sphinx.ext.*') or your custom ones.
+extensions = ['sphinx.ext.autodoc', 'sphinx.ext.intersphinx', 'sphinx.ext.todo']
+
+# Add any paths that contain templates here, relative to this directory.
+templates_path = ['_templates']
+
+# The suffix of source filenames.
+source_suffix = '.rst'
+
+# The encoding of source files.
+#source_encoding = 'utf-8-sig'
+
+# The master toctree document.
+master_doc = 'index'
+
+# General information about the project.
+project = u'ifupdown2'
+copyright = u'2014, Roopa Prabhu'
+
+# The version info for the project you're documenting, acts as replacement for
+# |version| and |release|, also used in various other places throughout the
+# built documents.
+#
+# The short X.Y version.
+version = '0.1'
+# The full version, including alpha/beta/rc tags.
+release = '0.1'
+
+# The language for content autogenerated by Sphinx. Refer to documentation
+# for a list of supported languages.
+#language = None
+
+# There are two options for replacing |today|: either, you set today to some
+# non-false value, then it is used:
+#today = ''
+# Else, today_fmt is used as the format for a strftime call.
+#today_fmt = '%B %d, %Y'
+
+# List of patterns, relative to source directory, that match files and
+# directories to ignore when looking for source files.
+exclude_patterns = []
+
+# The reST default role (used for this markup: `text`) to use for all documents.
+#default_role = None
+
+# If true, '()' will be appended to :func: etc. cross-reference text.
+#add_function_parentheses = True
+
+# If true, the current module name will be prepended to all description
+# unit titles (such as .. function::).
+#add_module_names = True
+
+# If true, sectionauthor and moduleauthor directives will be shown in the
+# output. They are ignored by default.
+#show_authors = False
+
+# The name of the Pygments (syntax highlighting) style to use.
+pygments_style = 'sphinx'
+
+# A list of ignored prefixes for module index sorting.
+#modindex_common_prefix = []
+
+
+# -- Options for HTML output ---------------------------------------------------
+
+# The theme to use for HTML and HTML Help pages.  See the documentation for
+# a list of builtin themes.
+html_theme = 'default'
+
+# Theme options are theme-specific and customize the look and feel of a theme
+# further.  For a list of options available for each theme, see the
+# documentation.
+#html_theme_options = {}
+
+# Add any paths that contain custom themes here, relative to this directory.
+#html_theme_path = []
+
+# The name for this set of Sphinx documents.  If None, it defaults to
+# "<project> v<release> documentation".
+#html_title = None
+
+# A shorter title for the navigation bar.  Default is the same as html_title.
+#html_short_title = None
+
+# The name of an image file (relative to this directory) to place at the top
+# of the sidebar.
+#html_logo = None
+
+# The name of an image file (within the static path) to use as favicon of the
+# docs.  This file should be a Windows icon file (.ico) being 16x16 or 32x32
+# pixels large.
+#html_favicon = None
+
+# Add any paths that contain custom static files (such as style sheets) here,
+# relative to this directory. They are copied after the builtin static files,
+# so a file named "default.css" will overwrite the builtin "default.css".
+html_static_path = ['_static']
+
+# If not '', a 'Last updated on:' timestamp is inserted at every page bottom,
+# using the given strftime format.
+#html_last_updated_fmt = '%b %d, %Y'
+
+# If true, SmartyPants will be used to convert quotes and dashes to
+# typographically correct entities.
+#html_use_smartypants = True
+
+# Custom sidebar templates, maps document names to template names.
+#html_sidebars = {}
+
+# Additional templates that should be rendered to pages, maps page names to
+# template names.
+#html_additional_pages = {}
+
+# If false, no module index is generated.
+#html_domain_indices = True
+
+# If false, no index is generated.
+#html_use_index = True
+
+# If true, the index is split into individual pages for each letter.
+#html_split_index = False
+
+# If true, links to the reST sources are added to the pages.
+#html_show_sourcelink = True
+
+# If true, "Created using Sphinx" is shown in the HTML footer. Default is True.
+#html_show_sphinx = True
+
+# If true, "(C) Copyright ..." is shown in the HTML footer. Default is True.
+#html_show_copyright = True
+
+# If true, an OpenSearch description file will be output, and all pages will
+# contain a <link> tag referring to it.  The value of this option must be the
+# base URL from which the finished HTML is served.
+#html_use_opensearch = ''
+
+# This is the file name suffix for HTML files (e.g. ".xhtml").
+#html_file_suffix = None
+
+# Output file base name for HTML help builder.
+htmlhelp_basename = 'ifupdown2doc'
+
+
+# -- Options for LaTeX output --------------------------------------------------
+
+latex_elements = {
+# The paper size ('letterpaper' or 'a4paper').
+#'papersize': 'letterpaper',
+
+# The font size ('10pt', '11pt' or '12pt').
+#'pointsize': '10pt',
+
+# Additional stuff for the LaTeX preamble.
+#'preamble': '',
+}
+
+# Grouping the document tree into LaTeX files. List of tuples
+# (source start file, target name, title, author, documentclass [howto/manual]).
+latex_documents = [
+  ('index', 'ifupdown2.tex', u'ifupdown2 Documentation',
+   u'Roopa Prabhu', 'manual'),
+]
+
+# The name of an image file (relative to this directory) to place at the top of
+# the title page.
+#latex_logo = None
+
+# For "manual" documents, if this is true, then toplevel headings are parts,
+# not chapters.
+#latex_use_parts = False
+
+# If true, show page references after internal links.
+#latex_show_pagerefs = False
+
+# If true, show URL addresses after external links.
+#latex_show_urls = False
+
+# Documents to append as an appendix to all manuals.
+#latex_appendices = []
+
+# If false, no module index is generated.
+#latex_domain_indices = True
+
+
+# -- Options for manual page output --------------------------------------------
+
+# One entry per manual page. List of tuples
+# (source start file, name, description, authors, manual section).
+man_pages = [
+    ('index', 'ifupdown2', u'ifupdown2 Documentation',
+     [u'Roopa Prabhu'], 1)
+]
+
+# If true, show URL addresses after external links.
+#man_show_urls = False
+
+
+# -- Options for Texinfo output ------------------------------------------------
+
+# Grouping the document tree into Texinfo files. List of tuples
+# (source start file, target name, title, author,
+#  dir menu entry, description, category)
+texinfo_documents = [
+  ('index', 'ifupdown2', u'ifupdown2 Documentation',
+   u'Roopa Prabhu', 'ifupdown2', 'One line description of project.',
+   'Miscellaneous'),
+]
+
+# Documents to append as an appendix to all manuals.
+#texinfo_appendices = []
+
+# If false, no module index is generated.
+#texinfo_domain_indices = True
+
+# How to display URL addresses: 'footnote', 'no', or 'inline'.
+#texinfo_show_urls = 'footnote'
+
+
+# Example configuration for intersphinx: refer to the Python standard library.
+intersphinx_mapping = {'http://docs.python.org/': None}
diff --git a/docs/source/developmentcorner.rst b/docs/source/developmentcorner.rst
new file mode 100644 (file)
index 0000000..960d688
--- /dev/null
@@ -0,0 +1,72 @@
+Development Corner
+==================
+
+Getting started
+---------------
+Unlike original ifupdown, all interface configuration is moved to external
+python modules. That includes inet, inet6 and dhcp configurations.
+
+* if you are looking at fixing bugs or adding new features to the ifupdown2
+  infrastructure package, pls look at the apiref, documentation and code
+  for python-ifupdown2
+
+
+Writing a ifupdown2 addon module
+--------------------------------
+Addon modules are a nice way to add additional functionality to ifupdown2.
+Typically a new addon module will include support for a new network interface
+configuration which is not already supported by existing ifupdown2 addon
+modules.
+
+ifupdown2 addon modules are written in python. python-ifupdown2 package
+comes with default addon modules. All addon modules are installed under
+/usr/share/ifupdownaddons directory.
+
+The center of the universe for an addon module is the 'class iface' object
+exported by the python-ifupdown2 package.
+
+The iface object is modeled after an iface entry in the user provided network
+configuration file (eg. /etc/network/interfaces). For more details see
+the api reference for the iface class.
+
+ifupdown2 dynamically loads a python addon module. It expects the addon module
+to implement a few methods.
+
+* all addon modules must inherit from moduleBase class
+* the module must implement a class by the same name
+* the network interface object (class iface) and the operation to be performed
+  is passed to the modules. Operation can be any of 'pre-up', 'up', 'post-up',
+  'pre-down', 'down', 'post-down', 'query-check', 'query-running'.
+  The module can choose to support a subset or all operations.
+  In cases when the operation is query-check, the module must compare between
+  the given and running state and return the checked state of the object in
+  queryobjcur passed as argument to the run menthod.
+* the python addon class must provide a few methods:
+    * run() : method to configure the interface.
+    * get_ops() : must return a list of operations it supports.
+      eg: 'pre-up', 'post-down'
+    * get_dependent_ifacenames() : must return a list of interfaces the
+      supported interface is dependent on. This is used to build the
+      dependency list for sorting and executing interfaces in dependency order.
+    * if the module supports -r option to ifquery, ie ability to construct the
+      ifaceobj from running state, it can optionally implement the
+      get_dependent_ifacenames_running() method, to return the list of
+      dependent interfaces derived from running state of the interface.
+      This is different from get_dependent_ifacenames() where the dependent
+      interfaces are derived from the interfaces config file (provided by the
+      user).
+    * provide a dictionary of all supported attributes in the _modinfo
+      attribute. This is useful for syntax help and man page generation.
+
+python-ifupdown2 package also installs ifupdownaddons python package
+that contains helper modules for all addon modules.
+
+see example address handling module /usr/share/ifupdownaddons/address.py
+
+API reference
+-------------
+.. toctree::
+   :maxdepth: 2
+
+   addonsapiref.rst
+   addonshelperapiref.rst
diff --git a/docs/source/gettingstarted.rst b/docs/source/gettingstarted.rst
new file mode 100644 (file)
index 0000000..4d7f6cb
--- /dev/null
@@ -0,0 +1,27 @@
+Getting Started
+===============
+
+Prerequisites
+-------------
+* python-ifupdown2 is currently only tested on debian wheezy
+* python-ifupdown2 needs python version 2.6 or greater
+* Depends on: python-stdeb (for deb builds), python-docutils
+  (for rst2man), python-argcomplete, 'python-ipaddr'
+* Depends on python-gvgen package for printing interface graphs (this will be made optional in the future)
+* Optional dependency for template engine: python-mako
+
+
+Building
+--------
+$git clone <ifupdown2 git url> ifupdown2
+
+$cd ifupdown2/ifupdown2
+
+$./build.sh
+
+Installing
+----------
+install generated python-ifupdown2-<ver>.deb
+
+$dpkg -i <python-ifupdown2-<ver>.deb
+
diff --git a/docs/source/images/interfaces.png b/docs/source/images/interfaces.png
new file mode 100644 (file)
index 0000000..fda6d92
Binary files /dev/null and b/docs/source/images/interfaces.png differ
diff --git a/docs/source/images/interfaces_all.png b/docs/source/images/interfaces_all.png
new file mode 100644 (file)
index 0000000..3e1ae9c
Binary files /dev/null and b/docs/source/images/interfaces_all.png differ
diff --git a/docs/source/index.rst b/docs/source/index.rst
new file mode 100644 (file)
index 0000000..fde8c80
--- /dev/null
@@ -0,0 +1,25 @@
+.. ifupdown2 documentation master file, created by
+   sphinx-quickstart on Sun Jul  6 23:49:20 2014.
+   You can adapt this file completely to your liking, but it should at least
+   contain the root `toctree` directive.
+
+Welcome to ifupdown2's documentation!
+=====================================
+
+Contents:
+
+.. toctree::
+   :maxdepth: 2
+
+   intro.rst
+   gettingstarted.rst
+   userguide.rst
+   developmentcorner.rst
+
+Indices and tables
+==================
+
+* :ref:`genindex`
+* :ref:`modindex`
+* :ref:`search`
+
diff --git a/docs/source/intro.rst b/docs/source/intro.rst
new file mode 100644 (file)
index 0000000..7293e3f
--- /dev/null
@@ -0,0 +1,31 @@
+python-ifupdown2
+----------------
+
+The python-ifupdown2 package provides the infrastructure for
+parsing /etc/network/interfaces file, loading, scheduling, template parsing,
+state management and interface dependency generation of interfaces.
+It dynamically loads python addon modules from /usr/share/ifupdownmodules.
+To remain compatible with other packages that depend on ifupdown, it also
+executes scripts under /etc/network/. To make the transition smoother, a
+python module under /usr/share/ifupdownmodules will override a script by
+the same name under /etc/network/. ifupdown2 publishes an interface object which
+is passed to all loadble python addon modules. All lodable modules are
+called for every interface declared in the /etc/network/interfaces file.
+
+Addon modules are responsible for applying interface configuration.
+python-ifupdown2 ships with a set of default addon modules. Each module can
+declare its own set of supported attributes. Each module is passed the iface
+object (which is a representation of /etc/network/interfaces
+iface entry). Each module is also passed the operation to be performed.
+
+Example modules are /usr/share/ifupdownmodules/address.py,
+/usr/share/ifupdownmodules/bridge.py etc
+
+The order in which these modules are invoked is listed in
+/var/lib/ifupdownaddons/addons.conf. There is an ifaddon utility in the works
+to better manage the module ordering.
+
+For more details on adding an addon module, see the section on adding python
+modules. For details on how to write a module, see the api reference and
+development documentation.
+
diff --git a/docs/source/userguide.rst b/docs/source/userguide.rst
new file mode 100644 (file)
index 0000000..c06e9d2
--- /dev/null
@@ -0,0 +1,447 @@
+.. index:: ifupdown
+
+.. _ifupdown:
+
+**********
+User Guide
+**********
+
+Keep the following points in mind before you start configuring interfaces using 
+``ifupdown2``:
+
+* IPv4 and IPv6 addresses for an interface can be listed in the same ``iface`` 
+  section. For examples, see ``/usr/share/doc/python-ifupdown2/examples/``.
+
+* Do not use a legacy interface alias. They are only supported for backward 
+  compatibility with ``ifupdown``. They do get configured, but ``ifquery`` has 
+  problems recognizing them.
+  
+* ``ifupdown`` only understands interfaces that were configured using 
+  ``ifupdown``. Any interfaces created with a command other than ``ifupdown`` 
+  (like ``brctl``) must be de-configured in the same manner.
+
+* Use globs for port lists wherever applicable. Regular expressions work as well, 
+  however regular expressions require all matching interfaces to be present in 
+  the ``interfaces`` file. And declaring all interfaces in the ``interfaces`` 
+  file leads to losing all the advantages that built-in interfaces provide.
+
+* Extensions to ``ifquery`` help with validation and debugging.
+
+* By default, ``ifupdown`` is quiet; use the verbose option ``-v`` when you want 
+  to know what is going on when bringing an interface down or up.
+  
+Contents
+========
+* `Commands`_
+* `Man Pages`_
+* `Configuration Files`_
+* `ifupdown Built-in Interfaces`_
+* `ifupdown Interface Dependencies`_
+* `Configuring IP Addresses`_
+* `Specifying User Commands`_
+* `Sourcing Interface File Snippets`_
+* `Using Globs for Port Lists`_
+* `Using Templates`_
+* `Using ifquery to Validate and Debug Interface Configurations`_
+* `Useful Links`_
+
+Commands
+========
+
+* ifdown
+* ifquery
+* ifreload
+* ifup
+
+Man Pages
+=========
+
+* man ifdown(8)
+* man ifquery(8)
+* man ifreload
+* man ifup(8)
+* man ifupdown-addons-interfaces(5)
+* man interfaces(5)
+
+Configuration Files
+===================
+
+* /etc/network/interfaces
+
+    
+ifupdown Built-in Interfaces
+============================
+
+``ifupdown`` understands VLAN interfaces and physical interfaces that may appear
+as dependents. There is no need to list them unless they need the specific
+configuration or they need to match a regular expression used in the
+``interfaces`` file. Use globs to avoid limitations with regular expressions.
+
+For example, swp1.100 and swp2.100 below do not need an entry in the 
+``interfaces`` file::
+
+    auto br-100
+    iface br-100
+        address 10.0.12.2/24
+        address 2001:dad:beef::3/64
+        bridge-ports swp1.100 swp2.100
+        bridge-stp on
+
+
+
+ifupdown Interface Dependencies
+===============================
+
+``ifupdown`` understands interface dependency relationships. When ``ifup`` and
+``ifdown`` are run with all interfaces, they always run with all interfaces
+in dependency order. When run with the interface list on the command line, the
+default behavior is to not run with dependents. But if there are any built-in 
+dependents, they will be brought up or down.
+
+To run with dependents when you specify the interface list, use the 
+``--with-depends`` option. ``--with-depends`` walks through all dependents
+in the dependency tree rooted at the interface you specify. Consider the
+following example configuration::
+
+    auto bond1
+    iface bond1
+        address 100.0.0.2/16
+        bond-slaves swp29 swp30
+        bond-mode 802.3ad
+        bond-miimon 100
+        bond-use-carrier 1
+        bond-lacp-rate 1
+        bond-min-links 1
+        bond-xmit-hash-policy layer3+4
+
+    auto bond2
+    iface bond2
+        address 100.0.0.5/16
+        bond-slaves swp31 swp32
+        bond-mode 802.3ad
+        bond-miimon 100
+        bond-use-carrier 1
+        bond-lacp-rate 1
+        bond-min-links 1
+        bond-xmit-hash-policy layer3+4
+
+    auto br2001
+    iface br2001
+        address 12.0.1.3/24
+        bridge-ports bond1.2001 bond2.2001
+        bridge-stp on
+
+Specifying ``ifup --with-depends br2001`` brings up all dependents: bond1.2001, 
+bond2.2001, bond1, bond2, bond1.2001, bond2.2001, swp29, swp30, swp31, swp32.
+
+Similarly, specifying ``ifdown --with-depends br2001`` brings down all 
+dependents: bond1.2001, bond2.2001, bond1, bond2, bond1.2001, bond2.2001, swp29, 
+swp30, swp31, swp32. 
+
+.. warning:: ``ifdown`` always deletes logical interfaces after bringing them 
+   down. Use the ``--admin-state`` option if you only want to administratively 
+   bring the interface up or down. In terms of the above example, 
+   ``ifdown br2001`` deletes ``br2001``.
+
+To guide you through which interfaces will be brought down and up, use the
+``--print-dependency`` option to get the list of dependents.
+
+Use ``ifup --print-dependency=list -a`` to get the dependency list of all 
+interfaces::
+
+    cumulus@switch:~$ sudo ifup --print-dependency=list -a
+    lo : None
+    eth0 : None
+    bond0 : ['swp25', 'swp26']
+    bond1 : ['swp29', 'swp30']
+    bond2 : ['swp31', 'swp32']
+    br0 : ['bond1', 'bond2']
+    bond1.2000 : ['bond1']
+    bond2.2000 : ['bond2']
+    br2000 : ['bond1.2000', 'bond2.2000']
+    bond1.2001 : ['bond1']
+    bond2.2001 : ['bond2']
+    br2001 : ['bond1.2001', 'bond2.2001']
+    swp40 : None
+    swp25 : None
+    swp26 : None
+    swp29 : None
+    swp30 : None
+    swp31 : None
+    swp32 : None
+
+To print the dependency list of a single interface, use::
+
+    cumulus@switch:~$ sudo ifup --print-dependency=list br2001
+    br2001 : ['bond1.2001', 'bond2.2001']
+    bond1.2001 : ['bond1']
+    bond2.2001 : ['bond2']
+    bond1 : ['swp29', 'swp30']
+    bond2 : ['swp31', 'swp32']
+    swp29 : None
+    swp30 : None
+    swp31 : None
+    swp32 : None
+
+
+To print the dependency information of an interface in ``dot`` format::
+
+    cumulus@switch:~$ sudo ifup --print-dependency=dot br2001
+    /* Generated by GvGen v.0.9 (http://software.inl.fr/trac/wiki/GvGen) */
+    digraph G {
+        compound=true;
+        node1 [label="br2001"];
+        node2 [label="bond1.2001"];
+        node3 [label="bond2.2001"];
+        node4 [label="bond1"];
+        node5 [label="bond2"];
+        node6 [label="swp29"];
+        node7 [label="swp30"];
+        node8 [label="swp31"];
+        node9 [label="swp32"];
+        node1->node2;
+        node1->node3;
+        node2->node4;
+        node3->node5;
+        node4->node6;
+        node4->node7;
+        node5->node8;
+        node5->node9;
+    }
+
+You can use ``dot`` to render the graph on an external system where ``dot`` is
+installed.
+
+.. image:: images/interfaces.png
+
+
+To print the dependency information of the entire ``interfaces`` file::
+
+    cumulus@switch:~$ sudo ifup --print-dependency=dot -a >interfaces_all.dot
+
+.. image:: images/interfaces_all.png
+   :width: 800px
+
+
+.. note: The '--print-dependency' option is available with the ``ifup``, 
+   ``ifdown`` and ``ifquery`` commands.
+
+
+Configuring IP Addresses
+========================
+
+In ``/etc/network/interfaces``, list all IP addresses as shown below under the 
+``iface`` section (see ``man interfaces`` for more information)::
+
+    auto swp1
+    iface swp1
+        address 12.0.0.1/30
+        address 12.0.0.2/30
+
+The address method and address family are not mandatory. They default to 
+``inet``/``inet6`` and ``static`` by default, but ``inet``/``inet6`` **must** be 
+specified if you need to specify ``dhcp`` or ``loopback``.
+
+You can specify both IPv4 and IPv6 addresses under the same ``iface`` section::
+
+    auto swp1
+    iface swp1
+        address 12.0.0.1/30
+        address 12.0.0.2/30
+        address 2001:dee:eeef:2::1/64
+
+Specifying User Commands
+========================
+
+You can specify additional user commands in the ``interfaces`` file. As shown in 
+the example below, the interface stanzas in ``/etc/network/interfaces`` can have 
+a command that runs at pre-up, up, post-up, pre-down, down, and post-down::
+
+    auto swp1
+    iface swp1
+        address 12.0.0.1/30
+        up /sbin/foo bar
+
+Any valid command can be hooked in the sequencing of bringing an interface up or 
+down, although commands should be limited in scope to network-related commands 
+associated with the particular interface.  
+
+For example, it wouldn't make sense to install some Debian package on ``ifup`` 
+of swp1, even though that is technically possible. See ``man interfaces`` for 
+more details.
+
+Sourcing Interface File Snippets
+================================
+
+Sourcing interface files helps organize and manage the ``interfaces(5)`` file. 
+For example::
+
+    cumulus@switch:~$ cat /etc/network/interfaces
+    # The loopback network interface
+    auto lo
+    iface lo inet loopback
+
+    # The primary network interface
+    auto eth0
+    iface eth0 inet dhcp
+
+    source /etc/network/interfaces.d/bond0
+
+
+The contents of the sourced file used above are::
+
+    cumulus@switch:~$ cat /etc/network/interfaces.d/bond0
+    auto bond0
+    iface bond0
+        address 14.0.0.9/30
+        address 2001:ded:beef:2::1/64
+        bond-slaves swp25 swp26
+        bond-mode 802.3ad
+        bond-miimon 100
+        bond-use-carrier 1
+        bond-lacp-rate 1
+        bond-min-links 1
+        bond-xmit-hash-policy layer3+4
+               
+Using Globs for Port Lists
+==========================
+
+Some modules support globs to describe port lists. You can use globs to specify 
+bridge ports and bond slaves::
+
+    auto br0
+    iface br0
+        bridge-ports glob swp1-6.100
+
+    auto br1
+    iface br1
+        bridge-ports glob swp7-9.100  swp11.100 glob swp15-18.100
+
+Using Templates
+===============
+
+``ifupdown2`` supports Mako-style templates. For more information see
+`www.makotemplates.org <http://www.makotemplates.org/>`_. The Mako template 
+engine is run over the ``interfaces`` file before parsing.
+
+Use the template to declare cookie-cutter bridges in the ``interfaces`` file::
+
+    %for v in [11,12]:
+    auto vlan${v}
+    iface vlan${v}
+        address 10.20.${v}.3/24
+        bridge-ports glob swp19-20.${v}
+        bridge-stp on
+    %endfor
+
+
+And use it to declare addresses in the ``interfaces`` file::
+
+    %for i in [1,12]:
+    auto swp${i}
+    iface swp${i}
+        address 10.20.${i}.3/24
+
+
+Using ifquery to Validate and Debug Interface Configurations
+============================================================
+
+You use ``ifquery`` to print parsed ``interfaces`` file entries.
+
+To use ``ifquery`` to pretty print ``iface`` entries from the ``interfaces`` 
+file, run::
+
+    cumulus@switch:~$ sudo ifquery bond0
+    auto bond0
+    iface bond0
+        address 14.0.0.9/30
+        address 2001:ded:beef:2::1/64
+        bond-slaves swp25 swp26
+        bond-mode 802.3ad
+        bond-miimon 100
+        bond-use-carrier 1
+        bond-lacp-rate 1
+        bond-min-links 1
+        bond-xmit-hash-policy layer3+4
+
+.. Use ``ifquery -a`` to pretty print all ``iface`` entries from the 
+   ``interfaces`` file.
+
+Use ``ifquery --check`` to check the current running state of an interface within 
+the ``interfaces`` file. It returns exit code ``0`` or ``1`` if the configuration 
+does not match::
+
+    cumulus@switch:~$ sudo ifquery --check bond0
+    iface bond0
+            bond-mode 802.3ad  (✓)
+            bond-miimon 100  (✓)
+            bond-use-carrier 1  (✓)
+            bond-lacp-rate 1  (✓)
+            bond-min-links 1  (✓)
+            bond-xmit-hash-policy layer3+4  (✓)
+            bond-slaves swp25 swp26  (✓)
+            address 14.0.0.9/30  (✓)
+            address 2001:ded:beef:2::1/64  (✓)
+
+.. note:: ``ifquery --check`` is an experimental feature.
+
+.. Use ``ifquery --check -a`` to check all interfaces.
+
+Use ``ifquery --running`` to print the running state of interfaces in the 
+``interfaces`` file format::
+
+    cumulus@switch:~$ sudo ifquery --running bond0
+    auto bond0
+    iface bond0
+        bond-xmit-hash-policy layer3+4
+        bond-miimon 100
+        bond-lacp-rate 1
+        bond-min-links 1
+        bond-slaves swp25 swp26
+        bond-mode 802.3ad
+        address 14.0.0.9/30
+        address 2001:ded:beef:2::1/64
+
+
+``ifquery --syntax-help`` provides help on all possible attributes supported in 
+the ``interfaces`` file. For complete syntax on the ``interfaces`` file, see 
+``man interfaces`` and ``man ifupdown-addons-interfaces``.
+
+``ifquery`` can dump information in JSON format::
+
+    cumulus@switch:~$ sudo ifquery --format=json bond0
+    {
+        "auto": true, 
+        "config": {
+            "bond-use-carrier": "1", 
+            "bond-xmit-hash-policy": "layer3+4", 
+            "bond-miimon": "100", 
+            "bond-lacp-rate": "1", 
+            "bond-min-links": "1", 
+            "bond-slaves": "swp25 swp26", 
+            "bond-mode": "802.3ad", 
+            "address": [
+                "14.0.0.9/30",
+                "2001:ded:beef:2::1/64"
+            ]
+        }, 
+        "addr_method": null, 
+        "name": "bond0", 
+        "addr_family": null
+    }
+
+.. By default ``ifquery`` outputs information in the ``interfaces`` format. Some 
+   options do take the ``--format`` option and can output in JSON format.
+
+
+Useful Links
+============
+
+* `<http://wiki.debian.org/NetworkConfiguration>`_
+* `<http://www.linuxfoundation.org/collaborate/workgroups/networking/bonding>`_
+* `<http://www.linuxfoundation.org/collaborate/workgroups/networking/bridge>`_
+* `<http://www.linuxfoundation.org/collaborate/workgroups/networking/vlan>`_
+
+.. Caveats and Errata
+.. ==================
+
diff --git a/ifupdown/__init__.py b/ifupdown/__init__.py
new file mode 100644 (file)
index 0000000..5f7d90a
--- /dev/null
@@ -0,0 +1,5 @@
+""" ifupdown2 package.
+
+.. moduleauthor:: Roopa Prabhu <roopa@cumulusnetworks.com>
+
+"""
diff --git a/ifupdown/exceptions.py b/ifupdown/exceptions.py
new file mode 100644 (file)
index 0000000..f6cc8b7
--- /dev/null
@@ -0,0 +1,23 @@
+#!/usr/bin/python
+#
+# Copyright 2014 Cumulus Networks, Inc. All rights reserved.
+# Author: Roopa Prabhu, roopa@cumulusnetworks.com
+#
+# ifupdown --
+#    exceptions
+#
+
+class Error(Exception):
+    """Base class for exceptions in ifupdown"""
+
+    pass
+
+class ifaceNotFoundError(Error):
+    pass
+
+
+class invalidValueError(Error):
+    pass
+
+class errorReadingStateError(Error):
+    pass
diff --git a/ifupdown/graph.py b/ifupdown/graph.py
new file mode 100644 (file)
index 0000000..49b1348
--- /dev/null
@@ -0,0 +1,89 @@
+#!/usr/bin/python
+#
+# Copyright 2014 Cumulus Networks, Inc. All rights reserved.
+# Author: Roopa Prabhu, roopa@cumulusnetworks.com
+#
+# graph --
+#    graph helper module for ifupdown
+#
+
+import logging
+import copy
+from collections import deque
+try:
+    from gvgen import *
+except ImportError, e:
+    pass
+
+class graph():
+    """ graph functions to sort and print interface graph """
+
+    def __init__(self):
+        self.logger = logging.getLogger('ifupdown.' +
+                    self.__class__.__name__)
+
+    @classmethod
+    def topological_sort_graphs_all(cls, dependency_graphs, indegrees_arg):
+        """ runs topological sort on interface list passed as dependency graph
+
+        Args:
+            **dependency_graphs** (dict): dependency graph with dependency
+                                          lists for interfaces 
+
+            **indegrees_arg** (dict): indegrees array for all interfaces
+        """
+        S = []
+        Q = deque()
+
+        indegrees = copy.deepcopy(indegrees_arg)
+        for ifname,indegree in indegrees.items():
+            if indegree == 0:
+                Q.append(ifname)
+
+        while len(Q):
+            # initialize queue
+            x = Q.popleft()
+
+            # Get dependents of x
+            dlist = dependency_graphs.get(x)
+            if not dlist:
+                S.append(x)
+                continue
+
+            for y in dlist:
+                indegrees[y] = indegrees.get(y) - 1
+                if indegrees.get(y) == 0:
+                    Q.append(y)
+
+            S.append(x)
+
+        for ifname,indegree in indegrees.items():
+            if indegree != 0:
+                raise Exception('cycle found involving iface %s' %ifname +
+                                ' (indegree %d)' %indegree)
+
+        return S
+
+    @classmethod
+    def generate_dots(cls, dependency_graph, indegrees):
+        """ spits out interface dependency graph in dot format
+
+        Args:
+            **dependency_graphs** (dict): dependency graph with dependency
+                                          lists for interfaces 
+
+            **indegrees_arg** (dict): indegrees array for all interfaces
+        """
+
+        gvgraph = GvGen()
+        graphnodes = {}
+        for v in dependency_graph.keys():
+            graphnodes[v] = gvgraph.newItem(v)
+
+        for i, v in graphnodes.items():
+            dlist = dependency_graph.get(i, [])
+            if not dlist:
+                continue
+            for d in dlist:
+                gvgraph.newLink(v, graphnodes.get(d))
+        gvgraph.dot()
diff --git a/ifupdown/iface.py b/ifupdown/iface.py
new file mode 100644 (file)
index 0000000..52e8476
--- /dev/null
@@ -0,0 +1,593 @@
+#!/usr/bin/python
+#
+# Copyright 2014 Cumulus Networks, Inc. All rights reserved.
+# Author: Roopa Prabhu, roopa@cumulusnetworks.com
+#
+# iface --
+#    interface object
+#
+
+"""ifupdown2 network interface object
+
+It is modeled based on the 'iface' section in /etc/network/interfaces
+file. But can be extended to include any other network interface format
+"""
+
+from collections import OrderedDict
+import logging
+import json
+
+class ifaceType():
+    UNKNOWN = 0x0
+    IFACE = 0x1
+    BRIDGE_VLAN = 0x2
+
+
+class ifaceRole():
+    """ ifaceRole is used to classify the ifaceobj.role of
+        MASTER or SLAVE where there is a bond or bridge
+        with bond-slaves or bridge-ports.  A bond in a bridge
+        is both a master and slave (0x3)
+    """
+    UNKNOWN = 0x0
+    SLAVE = 0x1
+    MASTER = 0x2
+
+class ifaceLinkKind():
+    """ ifaceLlinkKind is used to identify interfaces
+        in the ifaceobj.link_kind attribute. Dependents of the bridge or
+        bond have an ifaceobj.role attribute of SLAVE and the bridge or
+        bond itself has ifaceobj.role of MASTER.
+    """
+    UNKNOWN = 0x0
+    BRIDGE = 0x1
+    BOND = 0x2
+    VLAN = 0x4
+    VXLAN = 0x8
+
+class ifaceLinkType():
+    LINK_UNKNOWN = 0x0
+    LINK_SLAVE = 0x1
+    LINK_MASTER = 0x2
+    LINK_NA = 0x3
+
+class ifaceDependencyType():
+    """ Indicates type of dependency.
+
+        This class enumerates types of dependency relationships
+        between interfaces.
+
+        iface dependency relationships can be classified
+        into:
+         - link
+         - master/slave
+
+        In a 'link' dependency relationship, dependency can be shared
+        between interfaces. example: swp1.100 and
+        swp1.200 can both have 'link' swp1. swp1 is also a dependency
+        of swp1.100 and swp1.200. As you can see dependency
+        swp1 is shared between swp1.100 and swp1.200.
+         
+        In a master/slave relationship like bridge and
+        its ports: eg: bridge br0 and its ports swp1 and swp2.
+        dependency swp1 and swp2 cannot be shared with any other
+        interface with the same dependency relationship.
+        ie, swp1 and swp2 cannot be in a slave relationship
+        with another interface. Understanding the dependency type is
+        required for any semantic checks between dependencies.
+
+    """
+    UNKNOWN = 0x0
+    LINK = 0x1
+    MASTER_SLAVE = 0x2
+
+class ifaceStatus():
+    """Enumerates iface status """
+
+    UNKNOWN = 0x1
+    SUCCESS = 0x2
+    ERROR = 0x3
+    NOTFOUND = 0x4
+
+    @classmethod
+    def to_str(cls, state):
+        if state == cls.UNKNOWN:
+            return 'unknown'
+        elif state == cls.SUCCESS:
+            return 'success'
+        elif state == cls.ERROR:
+            return 'error'
+        elif state == cls.NOTFOUND:
+            return 'notfound'
+    
+    @classmethod
+    def from_str(cls, state_str):
+        if state_str == 'unknown':
+            return cls.UNKNOWN
+        elif state_str == 'success':
+            return cls.SUCCESS
+        elif state_str == 'error':
+            return cls.ERROR
+
+class ifaceState():
+    """Enumerates iface state """
+
+    UNKNOWN = 0x1
+    NEW = 0x2
+    PRE_UP = 0x3
+    UP = 0x4
+    POST_UP = 0x5
+    PRE_DOWN = 0x6
+    DOWN = 0x7
+    POST_DOWN = 0x8
+
+    # Pseudo states
+    QUERY_CHECKCURR = 0x9
+    QUERY_RUNNING = 0xa
+
+    @classmethod
+    def to_str(cls, state):
+        if state == cls.UNKNOWN:
+            return 'unknown'
+        elif state == cls.NEW:
+            return 'new'
+        elif state == cls.PRE_UP:
+            return 'pre-up'
+        elif state == cls.UP:
+            return 'up'
+        elif state == cls.POST_UP:
+            return 'post-up'
+        elif state == cls.PRE_DOWN:
+            return 'pre-down'
+        elif state == cls.DOWN:
+            return 'down'
+        elif state == cls.POST_DOWN:
+            return 'post-down'
+        elif state == cls.QUERY_CHECKCURR:
+            return 'query-checkcurr'
+        elif state == cls.QUERY_RUNNING:
+            return 'query-running'
+
+    @classmethod
+    def from_str(cls, state_str):
+        if state_str == 'unknown':
+            return cls.UNKNOWN
+        elif state_str == 'new':
+            return cls.NEW
+        elif state_str == 'pre-up':
+            return cls.PRE_UP
+        elif state_str == 'up':
+            return cls.UP
+        elif state_str == 'post-up':
+            return cls.POST_UP
+        elif state_str == 'pre-down':
+            return cls.PRE_DOWN
+        elif state_str == 'down':
+            return cls.DOWN
+        elif state_str == 'post-down':
+            return cls.POST_DOWN
+        elif state_str == 'query-checkcurr':
+            return cls.QUERY_CHECKCURR
+        elif state_str == 'query-running':
+            return cls.QUERY_RUNNING
+
+class ifaceJsonEncoder(json.JSONEncoder):
+    def default(self, o):
+        retconfig = {}
+        if o.config:
+            retconfig = dict((k, (v[0] if len(v) == 1 else v))
+                             for k,v in o.config.items())
+        return OrderedDict({'name' : o.name,
+                            'addr_method' : o.addr_method,
+                            'addr_family' : o.addr_family,
+                            'auto' : o.auto,
+                            'config' : retconfig})
+
+class ifaceJsonDecoder():
+    @classmethod
+    def json_to_ifaceobj(cls, ifaceattrdict):
+        ifaceattrdict['config'] = OrderedDict([(k, (v if isinstance(v, list)
+                                                else [v]))
+                                for k,v in ifaceattrdict.get('config',
+                                            OrderedDict()).items()])
+        return iface(attrsdict=ifaceattrdict)
+
+class iface():
+    """ ifupdown2 iface object class
+    
+    Attributes:
+        **name**      Name of the interface 
+
+        **addr_family**     Address family eg, inet, inet6. Can be None to
+                            indicate both address families
+
+        **addr_method**     Address method eg, static, manual or None for
+                            static address method
+
+        **config**          dictionary of config lines for this interface
+
+        **state**           Configuration state of an interface as defined by
+                            ifaceState
+
+        **status**          Configuration status of an interface as defined by
+                            ifaceStatus
+
+        **flags**           Internal flags used by iface processing
+
+        **priv_flags**      private flags owned by module using this class
+
+        **module_flags**    module flags owned by module using this class
+
+        **refcnt**          reference count, indicating number of interfaces
+                            dependent on this iface
+
+        **lowerifaces**     list of interface names lower to this interface or
+                            this interface depends on
+
+        **upperifaces**     list of interface names upper to this interface or
+                            the interfaces that depend on this interface 
+
+        **auto**            True if interface belongs to the auto class
+
+        **classes**         List of classes the interface belongs to
+
+        **env**             shell environment the interface needs during
+                            execution
+
+        **raw_config**      raw interface config from file
+    """
+
+    # flag to indicate that the object was created from pickled state
+    _PICKLED = 0x00000001
+    HAS_SIBLINGS = 0x00000010
+    IFACERANGE_ENTRY = 0x00000100
+    IFACERANGE_START = 0x00001000
+
+    version = '0.1'
+
+    def __init__(self, attrsdict={}):
+        self._set_attrs_from_dict(attrsdict)
+        self._config_status = {}
+        """dict with config status of iface attributes"""
+        self.state = ifaceState.NEW
+        """iface state (of type ifaceState) """
+        self.status = ifaceStatus.UNKNOWN
+        """iface status (of type ifaceStatus) """
+        self.status_str = None
+        """iface status str (string representing the status) """
+        self.flags = 0x0
+        """iface flags """
+        self.priv_flags = 0x0
+        """iface module flags dictionary with module name: flags"""
+        self.module_flags = {}
+        """iface priv flags. can be used by the external object manager """
+        self.refcnt = 0
+        """iface refcnt (incremented for each dependent this interface has) """
+        self.lowerifaces = None 
+        """lower iface list (in other words: slaves of this interface """
+        self.upperifaces = None
+        """upper iface list (in other words: master of this interface """
+        self.classes = []
+        """interface classes this iface belongs to """
+        self.env = None
+        """environment variable dict required for this interface to run"""
+        self.raw_config = []
+        """interface config/attributes in raw format (eg: as it appeared in the interfaces file)"""
+        self.linkstate = None
+        """linkstate of the interface"""
+        self.type = ifaceType.UNKNOWN
+        """interface type"""
+        self.priv_data = None
+        self.role = ifaceRole.UNKNOWN
+        self.realname = None
+        self.link_type = ifaceLinkType.LINK_UNKNOWN
+        self.link_kind = ifaceLinkKind.UNKNOWN
+
+        # The below attribute is used to disambiguate between various
+        # types of dependencies
+        self.dependency_type = ifaceDependencyType.UNKNOWN
+
+    def _set_attrs_from_dict(self, attrdict):
+        self.auto = attrdict.get('auto', False)
+        self.name = attrdict.get('name')
+        self.addr_family = attrdict.get('addr_family')
+        self.addr_method = attrdict.get('addr_method')
+        self.config = attrdict.get('config', OrderedDict())
+
+    def inc_refcnt(self):
+        """ increment refcnt of the interface. Usually used to indicate that
+        it has dependents """
+        self.refcnt += 1
+
+    def dec_refcnt(self):
+        """ decrement refcnt of the interface. Usually used to indicate that
+        it has lost its dependent """
+        self.refcnt -= 1
+
+    def is_config_present(self):
+        """ returns true if the interface has user provided config,
+        false otherwise """
+        addr_method = self.addr_method
+        if addr_method and addr_method in ['dhcp', 'dhcp6', 'loopback']:
+            return True
+        if not self.config:
+            return False
+        else:
+            return True
+
+    def set_class(self, classname):
+        """ appends class to the interfaces class list """
+        self.classes.append(classname)
+
+    def set_state_n_status(self, state, status):
+        """ sets state and status of an interface """
+        self.state = state
+        self.status = status
+
+    def set_flag(self, flag):
+        self.flags |= flag
+
+    def clear_flag(self, flag):
+        self.flags &= ~flag
+
+    def add_to_upperifaces(self, upperifacename):
+        """ add to the list of upperifaces """
+        if self.upperifaces:
+            if upperifacename not in self.upperifaces:
+                self.upperifaces.append(upperifacename)
+        else:
+            self.upperifaces = [upperifacename]
+
+    def get_attr_value(self, attr_name):
+        """ add to the list of upperifaces """
+        return self.config.get(attr_name)
+    
+    def get_attr_value_first(self, attr_name):
+        """ get first value of the specified attr name """
+        attr_value_list = self.config.get(attr_name)
+        if attr_value_list:
+            return attr_value_list[0]
+        return None
+
+    def get_attrs_value_first(self, attrs):
+        """ get first value of the first attr in the list.
+            Useful when you have multiple attrs representing the
+            same thing.
+        """
+        for attr in attrs:
+            attr_value_list = self.config.get(attr)
+            if attr_value_list:
+                return attr_value_list[0]
+        return None
+
+    def get_attr_value_n(self, attr_name, attr_index):
+        """ get n'th value of the specified attr name """
+        attr_value_list = self.config.get(attr_name)
+        if attr_value_list:
+            try:
+                return attr_value_list[attr_index]
+            except:
+                return None
+        return None
+
+    @property
+    def get_env(self):
+        """ get shell environment variables the interface must execute in """
+        if not self.env:
+            self.generate_env()
+        return self.env
+
+    def generate_env(self):
+        """ generate shell environment variables dict interface must execute
+        in. This is used to support legacy ifupdown scripts
+        """
+        env = {}
+        config = self.config
+        env['IFACE'] = self.name
+        for attr, attr_value in config.items():
+            attr_env_name = 'IF_%s' %attr.upper()
+            env[attr_env_name] = attr_value[0]
+        if env:
+            self.env = env
+
+    def update_config(self, attr_name, attr_value):
+        """ add attribute name and value to the interface config """
+        self.config.setdefault(attr_name, []).append(attr_value)
+
+    def replace_config(self, attr_name, attr_value):
+        """ add attribute name and value to the interface config """
+        self.config[attr_name] = [attr_value]
+
+    def delete_config(self, attr_name):
+        """ add attribute name and value to the interface config """
+        try:
+            del self.config[attr_name]
+        except:
+            pass
+
+    def update_config_dict(self, attrdict):
+        self.config.update(attrdict)
+
+    def update_config_with_status(self, attr_name, attr_value, attr_status=0):
+        """ add attribute name and value to the interface config and also
+        update the config_status dict with status of this attribute config """
+        if not attr_value:
+            attr_value = ''
+        self.config.setdefault(attr_name, []).append(attr_value)
+        self._config_status.setdefault(attr_name, []).append(attr_status)
+        # set global iface state
+        if attr_status == 1:
+            self.status = ifaceStatus.ERROR
+        elif self.status != ifaceStatus.ERROR:
+            # Not already error, mark success
+            self.status = ifaceStatus.SUCCESS
+
+    def check_n_update_config_with_status_many(self, ifaceobjorig, attr_names,
+                                               attr_status=0):
+        # set multiple attribute status to zero
+        # also updates status only if the attribute is present
+        for attr_name in attr_names:
+            if not ifaceobjorig.get_attr_value_first(attr_name):
+               continue
+            self.config.setdefault(attr_name, []).append('')
+            self._config_status.setdefault(attr_name, []).append(attr_status)
+
+    def get_config_attr_status(self, attr_name, idx=0):
+        """ get status of a attribute config on this interface.
+        
+        Looks at the iface _config_status dict"""
+        return self._config_status.get(attr_name, [])[idx]
+
+    def compare(self, dstiface):
+        """ compares iface object with iface object passed as argument
+
+        Returns True if object self is same as dstiface and False otherwise """
+
+        if self.name != dstiface.name: return False
+        if self.type != dstiface.type: return False
+        if self.addr_family != dstiface.addr_family: return False
+        if self.addr_method != dstiface.addr_method: return False
+        if self.auto != dstiface.auto: return False
+        if self.classes != dstiface.classes: return False
+        if len(self.config) != len(dstiface.config):
+            return False
+        if any(True for k in self.config if k not in dstiface.config):
+            return False
+        if any(True for k,v in self.config.items()
+                    if v != dstiface.config.get(k)): return False
+        return True
+
+
+    def __getstate__(self):
+        odict = self.__dict__.copy()
+        del odict['state']
+        del odict['status']
+        del odict['lowerifaces']
+        del odict['upperifaces']
+        del odict['refcnt']
+        del odict['_config_status']
+        del odict['flags']
+        del odict['priv_flags']
+        del odict['module_flags']
+        del odict['raw_config']
+        del odict['linkstate']
+        del odict['env']
+        del odict['link_type']
+        del odict['link_kind']
+        del odict['role']
+        del odict['dependency_type']
+        return odict
+
+    def __setstate__(self, dict):
+        self.__dict__.update(dict)
+        self._config_status = {}
+        self.state = ifaceState.NEW
+        self.status = ifaceStatus.UNKNOWN
+        self.refcnt = 0
+        self.flags = 0
+        self.lowerifaces = None
+        self.upperifaces = None
+        self.linkstate = None
+        self.env = None
+        self.role = ifaceRole.UNKNOWN
+        self.priv_flags = 0
+        self.module_flags = {}
+        self.raw_config = []
+        self.flags |= self._PICKLED
+        self.link_type = ifaceLinkType.LINK_NA
+        self.link_kind = ifaceLinkKind.UNKNOWN
+        self.dependency_type = ifaceDependencyType.UNKNOWN
+
+    def dump_raw(self, logger):
+        indent = '  '
+        if self.auto:
+            print 'auto %s' %self.name
+        print (self.raw_config[0])
+        for i in range(1, len(self.raw_config)):
+            print(indent + self.raw_config[i])
+        
+    def dump(self, logger):
+        indent = '\t'
+        logger.info(self.name + ' : {')
+        logger.info(indent + 'family: %s' %self.addr_family)
+        logger.info(indent + 'method: %s' %self.addr_method)
+        logger.info(indent + 'flags: %x' %self.flags)
+        logger.info(indent + 'state: %s'
+                %ifaceState.to_str(self.state))
+        logger.info(indent + 'status: %s'
+                %ifaceStatus.to_str(self.status))
+        logger.info(indent + 'refcnt: %d' %self.refcnt)
+        d = self.lowerifaces
+        if d:
+            logger.info(indent + 'lowerdevs: %s' %str(d))
+        else:
+            logger.info(indent + 'lowerdevs: None')
+
+        logger.info(indent + 'config: ')
+        config = self.config
+        if config:
+            logger.info(indent + indent + str(config))
+        logger.info('}')
+
+    def dump_pretty(self, with_status=False,
+                    successstr='success', errorstr='error',
+                    unknownstr='unknown', use_realname=False):
+        indent = '\t'
+        outbuf = ''
+        if use_realname and self.realname:
+            name = '%s' %self.realname
+        else:
+            name = '%s' %self.name
+        if self.auto:
+            outbuf += 'auto %s\n' %name
+        ifaceline = ''
+        if self.type == ifaceType.BRIDGE_VLAN:
+            ifaceline += 'vlan %s' %name
+        else:
+            ifaceline += 'iface %s' %name
+        if self.addr_family:
+            ifaceline += ' %s' %self.addr_family
+        if self.addr_method:
+            ifaceline += ' %s' %self.addr_method
+        if with_status:
+            status_str = None
+            if (self.status == ifaceStatus.ERROR or
+                    self.status == ifaceStatus.NOTFOUND):
+                if self.status_str:
+                    ifaceline += ' (%s)' %self.status_str
+                status_str = errorstr
+            elif self.status == ifaceStatus.SUCCESS:
+                status_str = successstr
+            if status_str:
+               outbuf += '{0:65} {1:>8}'.format(ifaceline, status_str) + '\n'
+            else:
+                outbuf += ifaceline + '\n'
+            if self.status == ifaceStatus.NOTFOUND:
+                outbuf = (outbuf.encode('utf8')
+                    if isinstance(outbuf, unicode) else outbuf)
+                print outbuf + '\n'
+                return
+        else:
+            outbuf += ifaceline + '\n'
+        config = self.config
+        if config:
+            for cname, cvaluelist in config.items():
+                idx = 0
+                for cv in cvaluelist:
+                    if with_status:
+                        s = self.get_config_attr_status(cname, idx)
+                        if s == -1:
+                            status_str = unknownstr
+                        elif s == 1:
+                            status_str = errorstr
+                        elif s == 0:
+                            status_str = successstr
+                        outbuf += (indent + '{0:55} {1:>10}'.format(
+                                   '%s %s' %(cname, cv), status_str)) + '\n'
+                    else:
+                        outbuf += indent + '%s %s\n' %(cname, cv)
+                    idx += 1
+        if with_status:
+            outbuf = (outbuf.encode('utf8')
+                        if isinstance(outbuf, unicode) else outbuf)
+        print outbuf
diff --git a/ifupdown/iff.py b/ifupdown/iff.py
new file mode 100644 (file)
index 0000000..f191883
--- /dev/null
@@ -0,0 +1,36 @@
+#!/usr/bin/env python
+#
+# Copyright 2014 Cumulus Networks, Inc. All rights reserved.
+#
+# Author: Scott Feldman, sfeldma@cumulusnetworks.com
+#
+#
+# from /usr/include/linux/if.h
+#
+
+# Standard interface flags (netdevice->flags).
+
+IFF_UP = 0x1                  # interface is up
+IFF_BROADCAST = 0x2           # broadcast address valid
+IFF_DEBUG = 0x4               # turn on debugging
+IFF_LOOPBACK = 0x8            # is a loopback net
+IFF_POINTOPOINT = 0x10        # interface is has p-p link
+IFF_NOTRAILERS = 0x20         # avoid use of trailers
+IFF_RUNNING = 0x40            # interface RFC2863 OPER_UP
+IFF_NOARP = 0x80              # no ARP protocol
+IFF_PROMISC = 0x100           # receive all packets
+IFF_ALLMULTI = 0x200          # receive all multicast packets
+
+IFF_MASTER = 0x400            # master of a load balancer
+IFF_SLAVE = 0x800             # slave of a load balancer
+
+IFF_MULTICAST = 0x1000        # Supports multicast
+
+IFF_PORTSEL = 0x2000          # can set media type
+IFF_AUTOMEDIA = 0x4000        # auto media select active
+IFF_DYNAMIC = 0x8000          # dialup device with changing addresses
+
+IFF_LOWER_UP = 0x10000        # driver signals L1 up
+IFF_DORMANT = 0x20000         # driver signals dormant
+
+IFF_ECHO = 0x40000            # echo sent packets
diff --git a/ifupdown/ifupdownbase.py b/ifupdown/ifupdownbase.py
new file mode 100644 (file)
index 0000000..2a6b480
--- /dev/null
@@ -0,0 +1,72 @@
+#!/usr/bin/python
+#
+# Copyright 2014 Cumulus Networks, Inc. All rights reserved.
+# Author: Roopa Prabhu, roopa@cumulusnetworks.com
+#
+# ifupdownBase --
+#    base object for various ifupdown objects
+#
+
+import logging
+import subprocess
+import re
+import os
+from iface import *
+import rtnetlink_api as rtnetlink_api
+
+class ifupdownBase(object):
+
+    def __init__(self):
+        modulename = self.__class__.__name__
+        self.logger = logging.getLogger('ifupdown.' + modulename)
+
+    def exec_command(self, cmd, cmdenv=None, nowait=False):
+        cmd_returncode = 0
+        cmdout = ''
+        try:
+            self.logger.info('Executing ' + cmd)
+            if self.DRYRUN:
+                return cmdout
+            ch = subprocess.Popen(cmd.split(),
+                    stdout=subprocess.PIPE,
+                    shell=False, env=cmdenv,
+                    stderr=subprocess.STDOUT,
+                    close_fds=True)
+            cmdout = ch.communicate()[0]
+            cmd_returncode = ch.wait()
+        except OSError, e:
+            raise Exception('could not execute ' + cmd +
+                    '(' + str(e) + ')')
+        if cmd_returncode != 0:
+            raise Exception('error executing cmd \'%s\'' %cmd +
+                '\n(' + cmdout.strip('\n ') + ')')
+        return cmdout
+
+    def ignore_error(self, errmsg):
+        if (self.FORCE == True or re.search(r'exists', errmsg,
+            re.IGNORECASE | re.MULTILINE) is not None):
+            return True
+        return False
+
+    def log_warn(self, str):
+        if self.ignore_error(str) == False:
+            if self.logger.getEffectiveLevel() == logging.DEBUG:
+                traceback.print_stack()
+            self.logger.warn(str)
+        pass
+
+    def log_error(self, str):
+        if self.ignore_error(str) == False:
+            raise
+            #raise Exception(str)
+        else:
+            pass
+
+    def link_exists(self, ifacename):
+        return os.path.exists('/sys/class/net/%s' %ifacename)
+
+    def link_up(self, ifacename):
+        rtnetlink_api.rtnl_api.link_set(ifacename, "up")
+
+    def link_down(self, ifacename):
+        rtnetlink_api.rtnl_api.link_set(ifacename, "down")
diff --git a/ifupdown/ifupdownmain.py b/ifupdown/ifupdownmain.py
new file mode 100644 (file)
index 0000000..549dd50
--- /dev/null
@@ -0,0 +1,1403 @@
+#!/usr/bin/python
+#
+# Copyright 2014 Cumulus Networks, Inc. All rights reserved.
+# Author: Roopa Prabhu, roopa@cumulusnetworks.com
+#
+# ifupdownMain --
+#    ifupdown main module
+#
+
+import os
+import re
+import imp
+import pprint
+import logging
+import sys, traceback
+import copy
+import json
+from statemanager import *
+from networkinterfaces import *
+from iface import *
+from scheduler import *
+from collections import deque
+from collections import OrderedDict
+from graph import *
+from sets import Set
+
+"""
+.. module:: ifupdownmain
+:synopsis: main module for ifupdown package
+
+.. moduleauthor:: Roopa Prabhu <roopa@cumulusnetworks.com>
+
+"""
+
+_tickmark = u'\u2713'
+_crossmark = u'\u2717'
+_success_sym = '(%s)' %_tickmark
+_error_sym = '(%s)' %_crossmark
+
+class ifupdownFlags():
+    FORCE = False
+    DRYRUN = False
+    NOWAIT = False
+    PERFMODE = False
+    CACHE = False
+
+    # Flags
+    CACHE_FLAGS = 0x0
+
+class ifupdownMain(ifupdownBase):
+    """ ifupdown2 main class """
+
+    # Flags
+    WITH_DEPENDS = False
+    ALL = False
+    IFACE_CLASS = False
+    COMPAT_EXEC_SCRIPTS = False
+    STATEMANAGER_ENABLE = True
+    STATEMANAGER_UPDATE = True
+    ADDONS_ENABLE = False
+
+    # priv flags to mark iface objects
+    BUILTIN = 0x0001
+    NOCONFIG = 0x0010
+
+    scripts_dir='/etc/network'
+    addon_modules_dir='/usr/share/ifupdownaddons'
+    addon_modules_configfile='/var/lib/ifupdownaddons/addons.conf'
+
+    # iface dictionary in the below format:
+    # { '<ifacename>' : [<ifaceobject1>, <ifaceobject2> ..] }
+    # eg:
+    # { 'swp1' : [<iface swp1>, <iface swp2> ..] }
+    #
+    # Each ifaceobject corresponds to a configuration block for
+    # that interface
+    # The value in the dictionary is a list because the network
+    # interface configuration file supports more than one iface section
+    # in the interfaces file
+    ifaceobjdict = OrderedDict()
+
+    # iface dictionary representing the curr running state of an iface
+    # in the below format:
+    # {'<ifacename>' : <ifaceobject>}
+    ifaceobjcurrdict = OrderedDict()
+
+    # Dictionary representing operation and modules
+    # for every operation
+    module_ops = OrderedDict([('pre-up', []),
+                              ('up' , []),
+                              ('post-up' , []),
+                              ('query-checkcurr', []),
+                              ('query-running', []),
+                              ('query-dependency', []),
+                              ('query', []),
+                              ('query-raw', []),
+                              ('pre-down', []),
+                              ('down' , []),
+                              ('post-down' , [])])
+
+    # For old style /etc/network/ bash scripts
+    script_ops = OrderedDict([('pre-up', []),
+                                    ('up' , []),
+                                    ('post-up' , []),
+                                    ('pre-down', []),
+                                    ('down' , []),
+                                    ('post-down' , [])])
+
+    # Handlers for ops that ifupdown2 owns
+    def run_up(self, ifaceobj):
+        # Skip link sets on ifaceobjs of type 'vlan' (used for l2 attrs).
+        # there is no real interface behind it
+        if ifaceobj.type == ifaceType.BRIDGE_VLAN:
+            return
+        if (ifaceobj.addr_method and
+            ifaceobj.addr_method == 'manual'):
+            return
+        if self._delay_admin_state:
+            self._delay_admin_state_iface_queue.append(ifaceobj.name)
+            return
+        # If this object is a link slave, ie its link is controlled
+        # by its link master interface, then dont set the link state.
+        # But do allow user to change state of the link if the interface
+        # is already with its link master (hence the master check).
+        if ifaceobj.link_type == ifaceLinkType.LINK_SLAVE:
+            return
+        if not self.link_exists(ifaceobj.name):
+           return
+        self.link_up(ifaceobj.name)
+
+    def run_down(self, ifaceobj):
+        # Skip link sets on ifaceobjs of type 'vlan' (used for l2 attrs)
+        # there is no real interface behind it
+        if ifaceobj.type == ifaceType.BRIDGE_VLAN:
+            return
+        if (ifaceobj.addr_method and
+            ifaceobj.addr_method == 'manual'):
+            return
+        if self._delay_admin_state:
+            self._delay_admin_state_iface_queue.append(ifaceobj.name)
+            return
+        # If this object is a link slave, ie its link is controlled
+        # by its link master interface, then dont set the link state.
+        # But do allow user to change state of the link if the interface
+        # is already with its link master (hence the master check).
+        if ifaceobj.link_type == ifaceLinkType.LINK_SLAVE:
+           return
+        if not self.link_exists(ifaceobj.name):
+           return
+        self.link_down(ifaceobj.name)
+
+    # ifupdown object interface operation handlers
+    ops_handlers = OrderedDict([('up', run_up),
+                                ('down', run_down)])
+
+    def run_sched_ifaceobj_posthook(self, ifaceobj, op):
+        if ((ifaceobj.priv_flags & self.BUILTIN) or
+            (ifaceobj.priv_flags & self.NOCONFIG)):
+            return
+        if self.STATEMANAGER_UPDATE:
+            self.statemanager.ifaceobj_sync(ifaceobj, op)
+
+    # ifupdown object interface scheduler pre and posthooks
+    sched_hooks = {'posthook' : run_sched_ifaceobj_posthook}
+
+    def __init__(self, config={},
+                 force=False, dryrun=False, nowait=False,
+                 perfmode=False, withdepends=False, njobs=1,
+                 cache=False, addons_enable=True, statemanager_enable=True,
+                 interfacesfile='/etc/network/interfaces',
+                 interfacesfileiobuf=None,
+                 interfacesfileformat='native'):
+        """This member function initializes the ifupdownmain object.
+
+        Kwargs:
+            config (dict):  config dict from /etc/network/ifupdown2/ifupdown2.conf
+            force (bool): force interface configuration
+            dryrun (bool): dryrun interface configuration
+            withdepends (bool): apply interface configuration on all depends
+            interfacesfile (str): interfaces file. default is /etc/network/interfaces
+            interfacesfileformat (str): default is 'native'. Other choices are 'json'
+
+        Raises:
+            AttributeError, KeyError """
+
+        self.logger = logging.getLogger('ifupdown')
+        self.FORCE = force
+        self.DRYRUN = dryrun
+        self.NOWAIT = nowait
+        self.PERFMODE = perfmode
+        self.WITH_DEPENDS = withdepends
+        self.STATEMANAGER_ENABLE = statemanager_enable
+        self.CACHE = cache
+        self.interfacesfile = interfacesfile
+        self.interfacesfileiobuf = interfacesfileiobuf
+        self.interfacesfileformat = interfacesfileformat
+        self.config = config
+        self.logger.debug(self.config)
+
+        self.type = ifaceType.UNKNOWN
+
+        # Can be used to provide hints for caching
+        self.CACHE_FLAGS = 0x0
+        self._DELETE_DEPENDENT_IFACES_WITH_NOCONFIG = False
+        self.ADDONS_ENABLE = addons_enable
+
+        # Copy flags into ifupdownFlags
+        # XXX: before we transition fully to ifupdownFlags
+        ifupdownFlags.FORCE = force
+        ifupdownFlags.DRYRUN = dryrun
+        ifupdownFlags.NOWAIT = nowait
+        ifupdownFlags.PERFMODE = perfmode
+        ifupdownFlags.CACHE = cache
+
+        self.ifaces = OrderedDict()
+        self.njobs = njobs
+        self.pp = pprint.PrettyPrinter(indent=4)
+        self.modules = OrderedDict({})
+        self.module_attrs = {}
+        
+        self.load_addon_modules(self.addon_modules_dir)
+        if self.COMPAT_EXEC_SCRIPTS:
+            self.load_scripts(self.scripts_dir)
+        self.dependency_graph = OrderedDict({})
+
+        self._cache_no_repeats = {}
+
+        if self.STATEMANAGER_ENABLE:
+            try:
+                self.statemanager = stateManager()
+                self.statemanager.read_saved_state()
+            except Exception, e:
+                # XXX Maybe we should continue by ignoring old state
+                self.logger.warning('error reading state (%s)' %str(e))
+                raise
+        else:
+            self.STATEMANAGER_UPDATE = False
+        self._delay_admin_state = True if self.config.get(
+                            'delay_admin_state_change', '0') == '1' else False
+        self._delay_admin_state_iface_queue = []
+        if self._delay_admin_state:
+            self.logger.info('\'delay_admin_state_change\' is set. admin ' +
+                             'state changes will be delayed till the end.')
+
+        self._link_master_slave = True if self.config.get(
+                      'link_master_slave', '0') == '1' else False
+        if self._link_master_slave:
+            self.logger.info('\'link_master_slave\' is set. slave admin ' +
+                             'state changes will be delayed till the ' +
+                             'masters admin state change.')
+
+    def link_master_slave_ignore_error(self, errorstr):
+        # If link master slave flag is set, 
+        # there may be cases where the lowerdev may not be
+        # up resulting in 'Network is down' error
+        # This can happen if the lowerdev is a LINK_SLAVE
+        # of another interface which is not up yet
+        # example of such a case:
+        #   bringing up a vlan on a bond interface and the bond
+        #   is a LINK_SLAVE of a bridge (in other words the bond is
+        #   part of a bridge) which is not up yet
+        if self._link_master_slave:
+           if 'Network is down':
+              return True
+        return False
+
+    def get_ifaceobjs(self, ifacename):
+        return self.ifaceobjdict.get(ifacename)
+
+    def get_ifaceobjs_saved(self, ifacename):
+        """ Return ifaceobjects from statemanager """
+        if self.STATEMANAGER_ENABLE:
+           return self.statemanager.get_ifaceobjs(ifacename)
+        else:
+           None
+
+    def get_ifaceobj_first(self, ifacename):
+        ifaceobjs = self.get_ifaceobjs(ifacename)
+        if ifaceobjs:
+            return ifaceobjs[0]
+        return None
+
+    def get_ifacenames(self):
+        return self.ifaceobjdict.keys()
+
+    def get_iface_obj_last(self, ifacename):
+        return self.ifaceobjdict.get(ifacename)[-1]
+
+
+    def must_follow_upperifaces(self, ifacename):
+        #
+        # XXX: This bleeds the knowledge of iface
+        # types in the infrastructure module.
+        # Cant think of a better fix at the moment.
+        # In future maybe the module can set a flag
+        # to indicate if we should follow upperifaces
+        #
+        ifaceobj = self.get_ifaceobj_first(ifacename)
+        if ifaceobj.type == ifaceType.BRIDGE_VLAN:
+            return False
+        return True
+
+    def create_n_save_ifaceobj(self, ifacename, priv_flags=None,
+                               increfcnt=False):
+        """ creates a iface object and adds it to the iface dictionary """
+        ifaceobj = iface()
+        ifaceobj.name = ifacename
+        ifaceobj.priv_flags = priv_flags
+        ifaceobj.auto = True
+        if not self._link_master_slave:
+            ifaceobj.link_type = ifaceLinkType.LINK_NA
+        if increfcnt:
+            ifaceobj.inc_refcnt()
+        self.ifaceobjdict[ifacename] = [ifaceobj]
+        return ifaceobj
+
+    def create_n_save_ifaceobjcurr(self, ifaceobj):
+        """ creates a copy of iface object and adds it to the iface
+            dict containing current iface objects 
+        """
+        ifaceobjcurr = iface()
+        ifaceobjcurr.name = ifaceobj.name
+        ifaceobjcurr.type = ifaceobj.type
+        ifaceobjcurr.lowerifaces = ifaceobj.lowerifaces
+        ifaceobjcurr.priv_flags = ifaceobj.priv_flags
+        ifaceobjcurr.auto = ifaceobj.auto
+        self.ifaceobjcurrdict.setdefault(ifaceobj.name,
+                                     []).append(ifaceobjcurr)
+        return ifaceobjcurr
+
+    def get_ifaceobjcurr(self, ifacename, idx=0):
+        ifaceobjlist = self.ifaceobjcurrdict.get(ifacename)
+        if not ifaceobjlist:
+            return None
+        if not idx:
+            return ifaceobjlist
+        else:
+            return ifaceobjlist[idx]
+
+    def get_ifaceobjrunning(self, ifacename):
+        return self.ifaceobjrunningdict.get(ifacename)
+
+    def get_iface_refcnt(self, ifacename):
+        """ Return iface ref count """
+        max = 0
+        ifaceobjs = self.get_ifaceobjs(ifacename)
+        if not ifaceobjs:
+            return 0
+        for i in ifaceobjs:
+            if i.refcnt > max:
+                max = i.refcnt
+        return max
+
+    def is_iface_builtin_byname(self, ifacename):
+        """ Returns true if iface name is a builtin interface.
+        
+        A builtin interface is an interface which ifupdown understands.
+        The following are currently considered builtin ifaces:
+            - vlan interfaces in the format <ifacename>.<vlanid>
+        """
+        return '.' in ifacename
+
+    def is_ifaceobj_builtin(self, ifaceobj):
+        """ Returns true if iface name is a builtin interface.
+        
+        A builtin interface is an interface which ifupdown understands.
+        The following are currently considered builtin ifaces:
+            - vlan interfaces in the format <ifacename>.<vlanid>
+        """
+        return (ifaceobj.priv_flags & self.BUILTIN)
+
+    def is_ifaceobj_noconfig(self, ifaceobj):
+        """ Returns true if iface object did not have a user defined config.
+       
+        These interfaces appear only when they are dependents of interfaces
+        which have user defined config
+        """
+        return (ifaceobj.priv_flags & self.NOCONFIG)
+
+    def is_iface_noconfig(self, ifacename):
+        """ Returns true if iface has no config """
+
+        ifaceobj = self.get_ifaceobj_first(ifacename)
+        if not ifaceobj: return True
+        return self.is_ifaceobj_noconfig(ifaceobj)
+
+    def check_shared_dependents(self, ifaceobj, dlist):
+        """ Check if dlist intersects with any other
+            interface with slave dependents.
+            example: bond and bridges.
+            This function logs such errors """
+        setdlist = Set(dlist)
+        for ifacename, ifacedlist in self.dependency_graph.items():
+            if not ifacedlist:
+                continue
+            check_depends = False
+            iobjs = self.get_ifaceobjs(ifacename)
+            for i in iobjs:
+                if (i.dependency_type == ifaceDependencyType.MASTER_SLAVE):
+                    check_depends = True
+            if check_depends:
+                common = Set(ifacedlist).intersection(setdlist)
+                if common:
+                    self.logger.error('misconfig..?. iface %s and %s '
+                            %(ifaceobj.name, ifacename) +
+                            'seem to share dependents/ports %s' %str(list(common)))
+
+    def preprocess_dependency_list(self, upperifaceobj, dlist, ops):
+        """ We go through the dependency list and
+            delete or add interfaces from the interfaces dict by
+            applying the following rules:
+                if flag _DELETE_DEPENDENT_IFACES_WITH_NOCONFIG is True:
+                    we only consider devices whose configuration was
+                    specified in the network interfaces file. We delete
+                    any interface whose config was not specified except
+                    for vlan devices. vlan devices get special treatment.
+                    Even if they are not present they are created and added
+                    to the ifacesdict
+                elif flag _DELETE_DEPENDENT_IFACES_WITH_NOCONFIG is False:
+                    we create objects for all dependent devices that are not
+                    present in the ifacesdict
+        """
+        del_list = []
+
+        if (upperifaceobj.dependency_type ==
+                    ifaceDependencyType.MASTER_SLAVE):
+            self.check_shared_dependents(upperifaceobj, dlist)
+
+        for d in dlist:
+            dilist = self.get_ifaceobjs(d)
+            if not dilist:
+                ni = None
+                if self.is_iface_builtin_byname(d):
+                    ni = self.create_n_save_ifaceobj(d,
+                            self.BUILTIN | self.NOCONFIG, True)
+                elif not self._DELETE_DEPENDENT_IFACES_WITH_NOCONFIG:
+                    ni = self.create_n_save_ifaceobj(d, self.NOCONFIG,
+                            True)
+                else:
+                    del_list.append(d)
+                if ni:
+                    if upperifaceobj.link_kind & \
+                           (ifaceLinkKind.BOND | ifaceLinkKind.BRIDGE):
+                        ni.role |= ifaceRole.SLAVE
+                    ni.add_to_upperifaces(upperifaceobj.name)
+                    if upperifaceobj.link_type == ifaceLinkType.LINK_MASTER:
+                        ni.link_type = ifaceLinkType.LINK_SLAVE
+            else:
+                for di in dilist:
+                    di.inc_refcnt()
+                    di.add_to_upperifaces(upperifaceobj.name)
+                    if upperifaceobj.link_kind & \
+                           (ifaceLinkKind.BOND | ifaceLinkKind.BRIDGE):
+                        di.role |= ifaceRole.SLAVE
+                    if upperifaceobj.link_type == ifaceLinkType.LINK_MASTER:
+                        di.link_type = ifaceLinkType.LINK_SLAVE
+        for d in del_list:
+            dlist.remove(d)
+
+    def query_dependents(self, ifaceobj, ops, ifacenames, type=None):
+        """ Gets iface dependents by calling into respective modules """
+        ret_dlist = []
+
+        # Get dependents for interface by querying respective modules
+        for module in self.modules.values():
+            try:
+                if ops[0] == 'query-running':
+                    if (not hasattr(module,
+                        'get_dependent_ifacenames_running')):
+                        continue
+                    dlist = module.get_dependent_ifacenames_running(ifaceobj)
+                else:
+                    if (not hasattr(module, 'get_dependent_ifacenames')):
+                        continue
+                    dlist = module.get_dependent_ifacenames(ifaceobj,
+                                        ifacenames)
+            except Exception, e:
+                self.logger.warn('%s: error getting dependent interfaces (%s)'
+                        %(ifaceobj.name, str(e)))
+                dlist = None
+                pass
+            if dlist: ret_dlist.extend(dlist)
+        return list(set(ret_dlist))
+
+
+    def populate_dependency_info(self, ops, ifacenames=None):
+        """ recursive function to generate iface dependency info """
+
+        if not ifacenames:
+            ifacenames = self.ifaceobjdict.keys()
+
+        iqueue = deque(ifacenames)
+        while iqueue:
+            i = iqueue.popleft()
+            # Go through all modules and find dependent ifaces
+            dlist = None
+            ifaceobj = self.get_ifaceobj_first(i)
+            if not ifaceobj: 
+                continue
+            dlist = ifaceobj.lowerifaces
+            if not dlist:
+                dlist = self.query_dependents(ifaceobj, ops, ifacenames)
+            else:
+                continue
+            if dlist:
+                self.preprocess_dependency_list(ifaceobj,
+                                                dlist, ops)
+                ifaceobj.lowerifaces = dlist
+                [iqueue.append(d) for d in dlist]
+            if not self.dependency_graph.get(i):
+                self.dependency_graph[i] = dlist
+
+    def _check_config_no_repeats(self, ifaceobj):
+        """ check if object has an attribute that is
+        restricted to a single object in the system.
+        if yes, warn and return """
+        for k,v in self._cache_no_repeats.items():
+            iv = ifaceobj.config.get(k)
+            if iv and iv[0] == v:
+                self.logger.error('ignoring interface %s. ' %ifaceobj.name +
+                        'Only one object with attribute ' +
+                        '\'%s %s\' allowed.' %(k, v))
+                return True
+        for k, v in self.config.get('no_repeats', {}).items():
+            iv = ifaceobj.config.get(k)
+            if iv and iv[0] == v:
+                self._cache_no_repeats[k] = v
+        return False
+
+    def _save_iface(self, ifaceobj):
+        if self._check_config_no_repeats(ifaceobj):
+           return
+        if not self._link_master_slave:
+           ifaceobj.link_type = ifaceLinkType.LINK_NA
+        currentifaceobjlist = self.ifaceobjdict.get(ifaceobj.name)
+        if not currentifaceobjlist:
+           self.ifaceobjdict[ifaceobj.name]= [ifaceobj]
+           return
+        if ifaceobj.compare(currentifaceobjlist[0]):
+            self.logger.warn('duplicate interface %s found' %ifaceobj.name)
+            return
+        if currentifaceobjlist[0].type == ifaceobj.type:
+            currentifaceobjlist[0].flags |= iface.HAS_SIBLINGS
+            ifaceobj.flags |= iface.HAS_SIBLINGS
+        self.ifaceobjdict[ifaceobj.name].append(ifaceobj)
+
+    def _iface_configattr_syntax_checker(self, attrname, attrval):
+        for m, mdict in self.module_attrs.items():
+            if not mdict:
+                continue
+            attrsdict = mdict.get('attrs')
+            try:
+                if attrsdict.get(attrname):
+                    return True
+            except AttributeError:
+                pass
+        return False
+
+    def _ifaceobj_syntax_checker(self, ifaceobj):
+        err = False
+        for attrname, attrvalue in ifaceobj.config.items():
+            found = False
+            for k, v in self.module_attrs.items():
+                if v and v.get('attrs', {}).get(attrname):
+                    found = True
+                    break
+            if not found:
+                err = True
+                self.logger.warn('%s: unsupported attribute \'%s\'' \
+                                 % (ifaceobj.name, attrname))
+                continue
+        return err
+
+    def read_iface_config(self):
+        """ Reads default network interface config /etc/network/interfaces. """
+        nifaces = networkInterfaces(self.interfacesfile,
+                        self.interfacesfileiobuf,
+                        self.interfacesfileformat,
+                        template_engine=self.config.get('template_engine'),
+                template_lookuppath=self.config.get('template_lookuppath'))
+        nifaces.subscribe('iface_found', self._save_iface)
+        nifaces.subscribe('validateifaceattr',
+                          self._iface_configattr_syntax_checker)
+        nifaces.subscribe('validateifaceobj', self._ifaceobj_syntax_checker)
+        nifaces.load()
+
+    def read_old_iface_config(self):
+        """ Reads the saved iface config instead of default iface config.
+        And saved iface config is already read by the statemanager """
+        self.ifaceobjdict = copy.deepcopy(self.statemanager.ifaceobjdict)
+
+    def _load_addon_modules_config(self):
+        """ Load addon modules config file """
+
+        with open(self.addon_modules_configfile, 'r') as f:
+            lines = f.readlines()
+            for l in lines:
+                try:
+                    litems = l.strip(' \n\t\r').split(',')
+                    if not litems or len(litems) < 2:
+                        continue
+                    operation = litems[0]
+                    mname = litems[1]
+                    self.module_ops[operation].append(mname)
+                except Exception, e:
+                    self.logger.warn('error reading line \'%s\'' %(l, str(e)))
+                    continue
+
+    def load_addon_modules(self, modules_dir):
+        """ load python modules from modules_dir
+
+        Default modules_dir is /usr/share/ifupdownmodules
+
+        """
+        self.logger.info('loading builtin modules from %s' %modules_dir)
+        self._load_addon_modules_config()
+        if not modules_dir in sys.path:
+            sys.path.append(modules_dir)
+        try:
+            for op, mlist in self.module_ops.items():
+                for mname in mlist:
+                    if self.modules.get(mname):
+                        continue
+                    mpath = modules_dir + '/' + mname + '.py'
+                    if os.path.exists(mpath):
+                        try:
+                            m = __import__(mname)
+                            mclass = getattr(m, mname)
+                        except:
+                            raise
+                        minstance = mclass(force=self.FORCE,
+                                        dryrun=self.DRYRUN,
+                                        nowait=self.NOWAIT,
+                                        perfmode=self.PERFMODE,
+                                        cache=self.CACHE,
+                                        cacheflags=self.CACHE_FLAGS)
+                        self.modules[mname] = minstance
+                        try:
+                            self.module_attrs[mname] = minstance.get_modinfo()
+                        except:
+                            pass
+        except: 
+            raise
+
+        # Assign all modules to query operations
+        self.module_ops['query-checkcurr'] = self.modules.keys()
+        self.module_ops['query-running'] = self.modules.keys()
+        self.module_ops['query-dependency'] = self.modules.keys()
+        self.module_ops['query'] = self.modules.keys()
+        self.module_ops['query-raw'] = self.modules.keys()
+
+
+    def _modules_help(self):
+        """ Prints addon modules supported syntax """
+
+        indent = '  '
+        for m, mdict in self.module_attrs.items():
+            if not mdict:
+                continue
+            print('%s: %s' %(m, mdict.get('mhelp')))
+            attrdict = mdict.get('attrs')
+            if not attrdict:
+                continue
+            try:
+                for attrname, attrvaldict in attrdict.items():
+                    if attrvaldict.get('compat', False):
+                        continue
+                    print('%s%s' %(indent, attrname))
+                    print('%shelp: %s' %(indent + '  ',
+                          attrvaldict.get('help', '')))
+                    print ('%srequired: %s' %(indent + '  ',
+                            attrvaldict.get('required', False)))
+                    default = attrvaldict.get('default')
+                    if default:
+                        print('%sdefault: %s' %(indent + '  ', default))
+
+                    validrange = attrvaldict.get('validrange')
+                    if validrange:
+                        print('%svalidrange: %s-%s'
+                              %(indent + '  ', validrange[0], validrange[1]))
+
+                    validvals = attrvaldict.get('validvals')
+                    if validvals:
+                        print('%svalidvals: %s'
+                              %(indent + '  ', ','.join(validvals)))
+
+                    examples = attrvaldict.get('example')
+                    if not examples:
+                        continue
+
+                    print '%sexample:' %(indent + '  ')
+                    for e in examples:
+                        print '%s%s' %(indent + '    ', e)
+            except:
+                pass
+            print ''
+            
+    def load_scripts(self, modules_dir):
+        """ loading user modules from /etc/network/.
+
+        Note that previously loaded python modules override modules found
+        under /etc/network if any
+
+        """
+
+        self.logger.info('looking for user scripts under %s' %modules_dir)
+        for op, mlist in self.script_ops.items():
+            msubdir = modules_dir + '/if-%s.d' %op
+            self.logger.info('loading scripts under %s ...' %msubdir)
+            try:
+                module_list = os.listdir(msubdir)
+                for module in module_list:
+                    if  self.modules.get(module) is not None:
+                        continue
+                    self.script_ops[op].append(
+                                    msubdir + '/' + module)
+            except: 
+                # continue reading
+                pass
+
+    def _sched_ifaces(self, ifacenames, ops, skipupperifaces=False,
+                      followdependents=True, sort=False):
+        self.logger.debug('scheduling \'%s\' for %s'
+                          %(str(ops), str(ifacenames)))
+        self._pretty_print_ordered_dict('dependency graph',
+                    self.dependency_graph)
+        return ifaceScheduler.sched_ifaces(self, ifacenames, ops,
+                        dependency_graph=self.dependency_graph,
+                        order=ifaceSchedulerFlags.INORDER
+                            if 'down' in ops[0]
+                                else ifaceSchedulerFlags.POSTORDER,
+                        followdependents=followdependents,
+                        skipupperifaces=skipupperifaces,
+                        sort=True if (sort or self.IFACE_CLASS) else False)
+
+    def _render_ifacename(self, ifacename):
+        new_ifacenames = []
+        vlan_match = re.match("^([\d]+)-([\d]+)", ifacename)
+        if vlan_match:
+            vlan_groups = vlan_match.groups()
+            if vlan_groups[0] and vlan_groups[1]:
+                [new_ifacenames.append('%d' %v)
+                    for v in range(int(vlan_groups[0]),
+                            int(vlan_groups[1])+1)]
+        return new_ifacenames
+
+    def _preprocess_ifacenames(self, ifacenames):
+        """ validates interface list for config existance.
+       
+        returns -1 if one or more interface not found. else, returns 0
+
+        """
+        new_ifacenames = []
+        err_iface = ''
+        for i in ifacenames:
+            ifaceobjs = self.get_ifaceobjs(i)
+            if not ifaceobjs:
+                # if name not available, render interface name and check again
+                rendered_ifacenames = utils.expand_iface_range(i)
+                if rendered_ifacenames:
+                    for ri in rendered_ifacenames:
+                        ifaceobjs = self.get_ifaceobjs(ri)
+                        if not ifaceobjs:
+                            err_iface += ' ' + ri
+                        else:
+                            new_ifacenames.append(ri)
+                else:
+                    err_iface += ' ' + i
+            else:
+                new_ifacenames.append(i)
+        if err_iface:
+            raise Exception('cannot find interfaces:%s' %err_iface)
+        return new_ifacenames 
+
+    def _iface_whitelisted(self, auto, allow_classes, excludepats, ifacename):
+        """ Checks if interface is whitelisted depending on set of parameters.
+
+        interfaces are checked against the allow_classes and auto lists.
+
+        """
+        if excludepats:
+            for e in excludepats:
+                if re.search(e, ifacename):
+                    return False
+        ifaceobjs = self.get_ifaceobjs(ifacename)
+        if not ifaceobjs:
+            self.logger.debug('iface %s' %ifacename + ' not found')
+            return False
+        # We check classes first
+        if allow_classes:
+            for i in ifaceobjs:
+                if i.classes:
+                    common = Set([allow_classes]).intersection(
+                                Set(i.classes))
+                    if common:
+                        return True
+            return False
+        if auto:
+            for i in ifaceobjs:
+                if i.auto:
+                    return True
+            return False
+        return True
+
+    def _compat_conv_op_to_mode(self, op):
+        """ Returns old op name to work with existing scripts """
+        if op == 'pre-up':
+            return 'start'
+        elif op == 'pre-down':
+            return 'stop'
+        else:
+            return op
+
+    def generate_running_env(self, ifaceobj, op):
+        """ Generates a dictionary with env variables required for
+        an interface. Used to support script execution for interfaces.
+        """
+
+        cenv = None
+        iface_env = ifaceobj.env
+        if iface_env:
+            cenv = os.environ
+            if cenv:
+                cenv.update(iface_env)
+            else:
+                cenv = iface_env
+            cenv['MODE'] = self._compat_conv_op_to_mode(op)
+        return cenv
+
+    def _save_state(self):
+        if not self.STATEMANAGER_ENABLE or not self.STATEMANAGER_UPDATE:
+            return
+        try:
+            # Update persistant iface states
+            self.statemanager.save_state()
+        except Exception, e:
+            if self.logger.isEnabledFor(logging.DEBUG):
+                t = sys.exc_info()[2]
+                traceback.print_tb(t)
+                self.logger.warning('error saving state (%s)' %str(e))
+
+    def set_type(self, type):
+        if type == 'iface':
+            self.type = ifaceType.IFACE
+        elif type == 'vlan':
+            self.type = ifaceType.BRIDGE_VLAN
+        else:
+            self.type = ifaceType.UNKNOWN
+
+    def _process_delay_admin_state_queue(self, op):
+        if not self._delay_admin_state_iface_queue:
+           return
+        if op == 'up':
+           func = self.link_up
+        elif op == 'down':
+           func = self.link_down
+        else:
+           return
+        for i in self._delay_admin_state_iface_queue:
+            try:
+                if self.link_exists(i):
+                   func(i)
+            except Exception, e:
+                self.logger.warn(str(e))
+                pass
+
+    def up(self, ops, auto=False, allow_classes=None, ifacenames=None,
+           excludepats=None, printdependency=None, syntaxcheck=False,
+           type=None, skipupperifaces=False):
+        """This brings the interface(s) up
+        
+        Args:
+            ops (list): list of ops to perform on the interface(s).
+            Eg: ['pre-up', 'up', 'post-up'
+
+        Kwargs:
+            auto (bool): act on interfaces marked auto
+            allow_classes (list): act on interfaces belonging to classes in the list
+            ifacenames (list): act on interfaces specified in this list
+            excludepats (list): list of patterns of interfaces to exclude
+            syntaxcheck (bool): only perform syntax check
+        """
+
+        self.set_type(type)
+
+        if allow_classes:
+            self.IFACE_CLASS = True
+        if not self.ADDONS_ENABLE: self.STATEMANAGER_UPDATE = False
+        if auto:
+            self.ALL = True
+            self.WITH_DEPENDS = True
+        try:
+            self.read_iface_config()
+        except Exception:
+            raise
+
+        # If only syntax check was requested, return here
+        if syntaxcheck:
+            return
+
+        if ifacenames:
+            ifacenames = self._preprocess_ifacenames(ifacenames)
+
+        # if iface list not given by user, assume all from config file
+        if not ifacenames: ifacenames = self.ifaceobjdict.keys()
+
+        # filter interfaces based on auto and allow classes
+        filtered_ifacenames = [i for i in ifacenames
+                               if self._iface_whitelisted(auto, allow_classes,
+                                                excludepats, i)]
+        if not filtered_ifacenames:
+            raise Exception('no ifaces found matching given allow lists')
+
+        if printdependency:
+            self.populate_dependency_info(ops, filtered_ifacenames)
+            self.print_dependency(filtered_ifacenames, printdependency)
+            return
+        else:
+            self.populate_dependency_info(ops)
+
+        try:
+            self._sched_ifaces(filtered_ifacenames, ops,
+                    skipupperifaces=skipupperifaces,
+                    followdependents=True if self.WITH_DEPENDS else False)
+        finally:
+            self._process_delay_admin_state_queue('up')
+            if not self.DRYRUN and self.ADDONS_ENABLE:
+                self._save_state()
+
+    def down(self, ops, auto=False, allow_classes=None, ifacenames=None,
+             excludepats=None, printdependency=None, usecurrentconfig=False,
+             type=None):
+        """ down an interface """
+
+        self.set_type(type)
+
+        if allow_classes:
+            self.IFACE_CLASS = True
+        if not self.ADDONS_ENABLE: self.STATEMANAGER_UPDATE = False
+        if auto:
+            self.ALL = True
+            self.WITH_DEPENDS = True
+        # For down we need to look at old state, unless usecurrentconfig
+        # is set
+        if (not usecurrentconfig and self.STATEMANAGER_ENABLE and
+                    self.statemanager.ifaceobjdict):
+            # Since we are using state manager objects,
+            # skip the updating of state manager objects
+            self.logger.debug('Looking at old state ..')
+            self.read_old_iface_config()
+        else:
+            # If no old state available 
+            try:
+                self.read_iface_config()
+            except Exception, e:
+                raise Exception('error reading iface config (%s)' %str(e))
+        if ifacenames:
+            # If iface list is given by the caller, always check if iface
+            # is present
+            try:
+               ifacenames = self._preprocess_ifacenames(ifacenames)
+            except Exception, e:
+               raise Exception('%s' %str(e) +
+                       ' (interface was probably never up ?)')
+
+        # if iface list not given by user, assume all from config file
+        if not ifacenames: ifacenames = self.ifaceobjdict.keys()
+
+        # filter interfaces based on auto and allow classes
+        filtered_ifacenames = [i for i in ifacenames
+                               if self._iface_whitelisted(auto, allow_classes,
+                                                excludepats, i)]
+        if not filtered_ifacenames:
+            raise Exception('no ifaces found matching given allow lists ' +
+                    '(or interfaces were probably never up ?)')
+
+        if printdependency:
+            self.populate_dependency_info(ops, filtered_ifacenames)
+            self.print_dependency(filtered_ifacenames, printdependency)
+            return
+        else:
+            self.populate_dependency_info(ops)
+
+        try:
+            self._sched_ifaces(filtered_ifacenames, ops,
+                    followdependents=True if self.WITH_DEPENDS else False)
+        finally:
+            self._process_delay_admin_state_queue('down')
+            if not self.DRYRUN and self.ADDONS_ENABLE:
+                self._save_state()
+
+    def query(self, ops, auto=False, allow_classes=None, ifacenames=None,
+              excludepats=None, printdependency=None,
+              format='native', type=None):
+        """ query an interface """
+
+        self.set_type(type)
+
+        if allow_classes:
+            self.IFACE_CLASS = True
+        if self.STATEMANAGER_ENABLE and ops[0] == 'query-savedstate':
+            return self.statemanager.dump_pretty(ifacenames)
+        self.STATEMANAGER_UPDATE = False
+        if auto:
+            self.logger.debug('setting flag ALL')
+            self.ALL = True
+            self.WITH_DEPENDS = True
+
+        if ops[0] == 'query-syntax':
+            self._modules_help()
+            return
+        elif ops[0] == 'query-running':
+            # create fake devices to all dependents that dont have config
+            map(lambda i: self.create_n_save_ifaceobj(i, self.NOCONFIG),
+                    ifacenames)
+        else:
+            try:
+                self.read_iface_config()
+            except Exception:
+                raise
+
+        if ifacenames and ops[0] != 'query-running':
+           # If iface list is given, always check if iface is present
+           ifacenames = self._preprocess_ifacenames(ifacenames)
+
+        # if iface list not given by user, assume all from config file
+        if not ifacenames: ifacenames = self.ifaceobjdict.keys()
+
+        # filter interfaces based on auto and allow classes
+        if ops[0] == 'query-running':
+            filtered_ifacenames = ifacenames
+        else:
+            filtered_ifacenames = [i for i in ifacenames
+                if self._iface_whitelisted(auto, allow_classes,
+                        excludepats, i)]
+        if not filtered_ifacenames:
+                raise Exception('no ifaces found matching ' +
+                        'given allow lists')
+
+        self.populate_dependency_info(ops)
+        if ops[0] == 'query-dependency' and printdependency:
+            self.print_dependency(filtered_ifacenames, printdependency)
+            return
+
+        if ops[0] == 'query':
+            return self.print_ifaceobjs_pretty(filtered_ifacenames, format)
+        elif ops[0] == 'query-raw':
+            return self.print_ifaceobjs_raw(filtered_ifacenames)
+
+        self._sched_ifaces(filtered_ifacenames, ops,
+                           followdependents=True if self.WITH_DEPENDS else False)
+
+        if ops[0] == 'query-checkcurr':
+            ret = self.print_ifaceobjscurr_pretty(filtered_ifacenames, format)
+            if ret != 0:
+                # if any of the object has an error, signal that silently
+                raise Exception('')
+        elif ops[0] == 'query-running':
+            self.print_ifaceobjsrunning_pretty(filtered_ifacenames, format)
+            return
+
+    def _reload_currentlyup(self, upops, downops, auto=True, allow=None,
+            ifacenames=None, excludepats=None, usecurrentconfig=False,
+            **extra_args):
+        """ reload currently up interfaces """
+        allow_classes = []
+        new_ifaceobjdict = {}
+
+        # Override auto to true
+        auto = True
+        try:
+            self.read_iface_config()
+        except:
+            raise
+        if not self.ifaceobjdict:
+            self.logger.warn("nothing to reload ..exiting.")
+            return
+        already_up_ifacenames = []
+        # generate dependency graph of interfaces
+        self.populate_dependency_info(upops)
+        if (not usecurrentconfig and self.STATEMANAGER_ENABLE
+                and self.statemanager.ifaceobjdict):
+            already_up_ifacenames = self.statemanager.ifaceobjdict.keys()
+
+        if not ifacenames: ifacenames = self.ifaceobjdict.keys()
+        filtered_ifacenames = [i for i in ifacenames
+                               if self._iface_whitelisted(auto, allow_classes,
+                               excludepats, i)]
+        
+        # Get already up interfaces that still exist in the interfaces file
+        already_up_ifacenames_not_present = Set(
+                        already_up_ifacenames).difference(ifacenames)
+        already_up_ifacenames_still_present = Set(
+                        already_up_ifacenames).difference(
+                        already_up_ifacenames_not_present)
+        interfaces_to_up = Set(already_up_ifacenames_still_present).union(
+                                            filtered_ifacenames)
+
+        if (already_up_ifacenames_not_present and
+                self.config.get('ifreload_currentlyup_down_notpresent') == '1'):
+           self.logger.info('reload: schedule down on interfaces: %s'
+                            %str(already_up_ifacenames_not_present))
+
+           # Save a copy of new iface objects and dependency_graph
+           new_ifaceobjdict = dict(self.ifaceobjdict)
+           new_dependency_graph = dict(self.dependency_graph)
+
+           # old interface config is read into self.ifaceobjdict
+           self.read_old_iface_config()
+
+           # reinitialize dependency graph 
+           self.dependency_graph = OrderedDict({})
+           self.populate_dependency_info(downops,
+                                         already_up_ifacenames_not_present)
+           self._sched_ifaces(already_up_ifacenames_not_present, downops,
+                              followdependents=False, sort=True)
+        else:
+           self.logger.debug('no interfaces to down ..')
+
+        # Now, run 'up' with new config dict
+        # reset statemanager update flag to default
+        if auto:
+            self.ALL = True
+            self.WITH_DEPENDS = True
+        if new_ifaceobjdict:
+            # and now, ifaceobjdict is back to current config
+            self.ifaceobjdict = new_ifaceobjdict
+            self.dependency_graph = new_dependency_graph
+
+        if not self.ifaceobjdict:
+           return
+        self.logger.info('reload: scheduling up on interfaces: %s'
+                         %str(interfaces_to_up))
+        self._sched_ifaces(interfaces_to_up, upops,
+                followdependents=True if self.WITH_DEPENDS else False)
+        if self.DRYRUN:
+            return
+        self._save_state()
+
+    def _reload_default(self, upops, downops, auto=False, allow=None,
+            ifacenames=None, excludepats=None, usecurrentconfig=False,
+            **extra_args):
+        """ reload interface config """
+        allow_classes = []
+        new_ifaceobjdict = {}
+
+        try:
+            self.read_iface_config()
+        except:
+            raise
+
+        if not self.ifaceobjdict:
+            self.logger.warn("nothing to reload ..exiting.")
+            return
+        # generate dependency graph of interfaces
+        self.populate_dependency_info(upops)
+        if (not usecurrentconfig and self.STATEMANAGER_ENABLE
+                and self.statemanager.ifaceobjdict):
+            # Save a copy of new iface objects and dependency_graph
+            new_ifaceobjdict = dict(self.ifaceobjdict)
+            new_dependency_graph = dict(self.dependency_graph)
+
+            # if old state is present, read old state and mark op for 'down'
+            # followed by 'up' aka: reload
+            # old interface config is read into self.ifaceobjdict
+            self.read_old_iface_config()
+            op = 'reload'
+        else:
+            # oldconfig not available, continue with 'up' with new config
+            op = 'up'
+
+        if not ifacenames: ifacenames = self.ifaceobjdict.keys()
+        if op == 'reload' and ifacenames:
+            filtered_ifacenames = [i for i in ifacenames
+                               if self._iface_whitelisted(auto, allow_classes,
+                               excludepats, i)]
+
+            # if config file had 'ifreload_down_changed' variable
+            # set, also look for interfaces that changed to down them
+            down_changed = int(self.config.get('ifreload_down_changed', '1'))
+
+            # Generate the interface down list
+            # Interfaces that go into the down list:
+            #   - interfaces that were present in last config and are not
+            #     present in the new config
+            #   - interfaces that were changed between the last and current
+            #     config
+            ifacedownlist = []
+            for ifname in filtered_ifacenames:
+                lastifaceobjlist = self.ifaceobjdict.get(ifname)
+                objidx = 0
+                # If interface is not present in the new file
+                # append it to the down list
+                newifaceobjlist = new_ifaceobjdict.get(ifname)
+                if not newifaceobjlist:
+                    ifacedownlist.append(ifname)
+                    continue
+                if not down_changed:
+                    continue
+                if len(newifaceobjlist) != len(lastifaceobjlist):
+                    ifacedownlist.append(ifname)
+                    continue
+
+                # If interface has changed between the current file
+                # and the last installed append it to the down list
+                # compare object list
+                for objidx in range(0, len(lastifaceobjlist)):
+                    oldobj = lastifaceobjlist[objidx]
+                    newobj = newifaceobjlist[objidx]
+                    if not newobj.compare(oldobj):
+                        ifacedownlist.append(ifname)
+                        continue
+
+            if ifacedownlist:
+                self.logger.info('reload: scheduling down on interfaces: %s'
+                                  %str(ifacedownlist))
+                # reinitialize dependency graph 
+                self.dependency_graph = OrderedDict({})
+                # Generate dependency info for old config
+                self.populate_dependency_info(downops, ifacedownlist)
+                try:
+                    self._sched_ifaces(ifacedownlist, downops,
+                                       followdependents=False,
+                                       sort=True)
+                except Exception, e:
+                    self.logger.error(str(e))
+                    pass
+                finally:
+                    self._process_delay_admin_state_queue('down')
+            else:
+                self.logger.debug('no interfaces to down ..')
+
+        # Now, run 'up' with new config dict
+        # reset statemanager update flag to default
+        if not new_ifaceobjdict:
+            return
+
+        if auto:
+            self.ALL = True
+            self.WITH_DEPENDS = True
+        # and now, we are back to the current config in ifaceobjdict
+        self.ifaceobjdict = new_ifaceobjdict
+        self.dependency_graph = new_dependency_graph
+        ifacenames = self.ifaceobjdict.keys()
+        filtered_ifacenames = [i for i in ifacenames
+                               if self._iface_whitelisted(auto, allow_classes,
+                               excludepats, i)]
+
+        self.logger.info('reload: scheduling up on interfaces: %s'
+                         %str(filtered_ifacenames))
+        try:
+            self._sched_ifaces(filtered_ifacenames, upops,
+                    followdependents=True if self.WITH_DEPENDS else False)
+        except Exception, e:
+            self.logger.error(str(e))
+            pass
+        finally:
+            self._process_delay_admin_state_queue('up')
+        if self.DRYRUN:
+            return
+        self._save_state()
+
+    def reload(self, *args, **kargs):
+        """ reload interface config """
+        self.logger.debug('reloading interface config ..')
+        if kargs.get('currentlyup', False):
+            self._reload_currentlyup(*args, **kargs)
+        else:
+            self._reload_default(*args, **kargs)
+
+    def _pretty_print_ordered_dict(self, prefix, argdict):
+        outbuf = prefix + ' {\n'
+        for k, vlist in argdict.items():
+            outbuf += '\t%s : %s\n' %(k, str(vlist))
+        self.logger.debug(outbuf + '}')
+
+    def print_dependency(self, ifacenames, format):
+        """ prints iface dependency information """
+
+        if not ifacenames:
+            ifacenames = self.ifaceobjdict.keys()
+        if format == 'list':
+            for k,v in self.dependency_graph.items():
+                print '%s : %s' %(k, str(v))
+        elif format == 'dot':
+            indegrees = {}
+            map(lambda i: indegrees.update({i :
+                self.get_iface_refcnt(i)}),
+                self.dependency_graph.keys())
+            graph.generate_dots(self.dependency_graph, indegrees)
+
+    def print_ifaceobjs_raw(self, ifacenames):
+        """ prints raw lines for ifaces from config file """
+
+        for i in ifacenames:
+            for ifaceobj in self.get_ifaceobjs(i):
+                if (self.is_ifaceobj_builtin(ifaceobj) or 
+                    not ifaceobj.is_config_present()):
+                    continue
+                ifaceobj.dump_raw(self.logger)
+                print '\n'
+                if self.WITH_DEPENDS and not self.ALL:
+                    dlist = ifaceobj.lowerifaces
+                    if not dlist: continue
+                    self.print_ifaceobjs_raw(dlist)
+
+    def _get_ifaceobjs_pretty(self, ifacenames, ifaceobjs, running=False):
+        """ returns iface obj list """
+
+        for i in ifacenames:
+            for ifaceobj in self.get_ifaceobjs(i):
+                if ((not running and self.is_ifaceobj_noconfig(ifaceobj)) or
+                    (running and not ifaceobj.is_config_present())):
+                    continue
+                ifaceobjs.append(ifaceobj)
+                if self.WITH_DEPENDS and not self.ALL:
+                    dlist = ifaceobj.lowerifaces
+                    if not dlist: continue
+                    self._get_ifaceobjs_pretty(dlist, ifaceobjs, running)
+
+    def print_ifaceobjs_pretty(self, ifacenames, format='native'):
+        """ pretty prints iface in format given by keyword arg format """
+
+        ifaceobjs = []
+        self._get_ifaceobjs_pretty(ifacenames, ifaceobjs)
+        if not ifaceobjs: return
+        if format == 'json':
+            print json.dumps(ifaceobjs, cls=ifaceJsonEncoder,
+                             indent=4, separators=(',', ': '))
+        else:
+            expand = int(self.config.get('ifquery_ifacename_expand_range', '0'))
+            for i in ifaceobjs:
+                if not expand and (i.flags & iface.IFACERANGE_ENTRY):
+                    # print only the first one
+                    if i.flags & iface.IFACERANGE_START:
+                       i.dump_pretty(use_realname=True)
+                else:
+                    i.dump_pretty()
+
+    def _get_ifaceobjscurr_pretty(self, ifacenames, ifaceobjs):
+        ret = 0
+        for i in ifacenames:
+            ifaceobjscurr = self.get_ifaceobjcurr(i)
+            if not ifaceobjscurr: continue
+            for ifaceobj in ifaceobjscurr:
+                if (ifaceobj.status == ifaceStatus.NOTFOUND or
+                    ifaceobj.status == ifaceStatus.ERROR):
+                    ret = 1
+                if self.is_ifaceobj_noconfig(ifaceobj):
+                    continue
+                ifaceobjs.append(ifaceobj)
+                if self.WITH_DEPENDS and not self.ALL:
+                    dlist = ifaceobj.lowerifaces
+                    if not dlist: continue
+                    dret = self._get_ifaceobjscurr_pretty(dlist, ifaceobjs)
+                    if dret: ret = 1
+        return ret
+
+    def print_ifaceobjscurr_pretty(self, ifacenames, format='native'):
+        """ pretty prints current running state of interfaces with status.
+
+        returns 1 if any of the interface has an error,
+        else returns 0
+        """
+
+        ifaceobjs = []
+        ret = self._get_ifaceobjscurr_pretty(ifacenames, ifaceobjs)
+        if not ifaceobjs: return
+        if format == 'json':
+            print json.dumps(ifaceobjs, cls=ifaceJsonEncoder, indent=2,
+                       separators=(',', ': '))
+        else:
+            map(lambda i: i.dump_pretty(with_status=True,
+                   successstr=self.config.get('ifquery_check_success_str',
+                                              _success_sym),
+                   errorstr=self.config.get('ifquery_check_error_str', _error_sym),
+                   unknownstr=self.config.get('ifquery_check_unknown_str', '')),
+                   ifaceobjs)
+        return ret
+
+    def print_ifaceobjsrunning_pretty(self, ifacenames, format='native'):
+        """ pretty prints iface running state """
+
+        ifaceobjs = []
+        self._get_ifaceobjs_pretty(ifacenames, ifaceobjs, running=True)
+        if not ifaceobjs: return
+        if format == 'json':
+            print json.dumps(ifaceobjs, cls=ifaceJsonEncoder, indent=2,
+                       separators=(',', ': '))
+        else:
+            map(lambda i: i.dump_pretty(), ifaceobjs)
+
+    def _dump(self):
+        print 'ifupdown main object dump'
+        print self.pp.pprint(self.modules)
+        print self.pp.pprint(self.ifaceobjdict)
+
+    def _dump_ifaceobjs(self, ifacenames):
+        for i in ifacenames:
+            ifaceobjs = self.get_ifaceobjs(i)
+            for i in ifaceobjs:
+                i.dump(self.logger)
+                print '\n'
diff --git a/ifupdown/netlink.py b/ifupdown/netlink.py
new file mode 100644 (file)
index 0000000..5a01043
--- /dev/null
@@ -0,0 +1,241 @@
+#!/usr/bin/env python
+#
+# Copyright 2014 Cumulus Networks, Inc. All rights reserved.
+# Author: Scott Feldman, sfeldma@cumulusnetworks.com
+#
+
+from os import strerror
+import select
+from time import time
+import socket
+from ctypes import *
+from errno import *
+import logging
+
+logger = logging.getLogger(__name__)
+
+#
+# from /usr/include/linux/netlink.h
+#
+
+NETLINK_ROUTE = 0            # Routing/device hook
+NETLINK_UNUSED = 1           # Unused number
+NETLINK_USERSOCK = 2         # Reserved for user mode socket protocols 
+NETLINK_FIREWALL = 3         # Firewalling hook
+NETLINK_INET_DIAG = 4        # INET socket monitoring
+NETLINK_NFLOG = 5            # netfilter/iptables ULOG 
+NETLINK_XFRM = 6             # ipsec 
+NETLINK_SELINUX = 7          # SELinux event notifications 
+NETLINK_ISCSI = 8            # Open-iSCSI 
+NETLINK_AUDIT = 9            # auditing 
+NETLINK_FIB_LOOKUP = 10        
+NETLINK_CONNECTOR = 11
+NETLINK_NETFILTER = 12       # netfilter subsystem 
+NETLINK_IP6_FW = 13
+NETLINK_DNRTMSG = 14         # DECnet routing messages 
+NETLINK_KOBJECT_UEVENT = 15  # Kernel messages to userspace 
+NETLINK_GENERIC = 16
+NETLINK_SCSITRANSPORT = 18   # SCSI Transports 
+NETLINK_ECRYPTFS = 19
+NETLINK_RDMA = 20
+NETLINK_CRYPTO = 21          # Crypto layer 
+
+NLMSG_NOOP = 1        # Nothing.
+NLMSG_ERROR = 2       # Error
+NLMSG_DONE = 3        # End of a dump
+NLMSG_OVERRUN = 4     # Data lost
+
+NETLINK_NO_ENOBUFS = 5
+
+SOL_NETLINK = 270
+
+class Nlmsghdr(Structure):
+
+    _fields_ = [
+        ('nlmsg_len', c_uint32),
+        ('nlmsg_type', c_uint16),
+        ('nlmsg_flags', c_uint16),
+        ('nlmsg_seq', c_uint32),
+        ('nlmsg_pid', c_uint32)
+    ]
+
+    def dump(self):
+        print 'nlmsg_len', self.nlmsg_len
+        print 'nlmsg_type', self.nlmsg_type
+        print 'nlmsg_flags 0x%04x' % self.nlmsg_flags
+        print 'nlmsg_seq', self.nlmsg_seq
+        print 'nlmsg_pid', self.nlmsg_pid
+
+# Flags values
+
+NLM_F_REQUEST = 1          # It is request message.
+NLM_F_MULTI = 2            # Multipart message, terminated by NLMSG_DONE
+NLM_F_ACK = 4              # Reply with ack, with zero or error code
+NLM_F_ECHO = 8             # Echo this request
+NLM_F_DUMP_INTR = 16       # Dump was inconsistent due to sequence change
+
+# Modifiers to GET request
+NLM_F_ROOT = 0x100         # specify tree root
+NLM_F_MATCH = 0x200        # return all matching
+NLM_F_ATOMIC = 0x400       # atomic GET
+NLM_F_DUMP = (NLM_F_ROOT|NLM_F_MATCH)
+
+# Modifiers to NEW request
+NLM_F_REPLACE = 0x100      # Override existing
+NLM_F_EXCL = 0x200         # Do not touch, if it exists
+NLM_F_CREATE = 0x400       # Create, if it does not exist
+NLM_F_APPEND = 0x800       # Add to end of list
+
+NLMSG_ALIGNTO = 4
+def NLMSG_ALIGN(len):
+    return (len + NLMSG_ALIGNTO - 1) & ~(NLMSG_ALIGNTO - 1)
+def NLMSG_HDRLEN():
+    return NLMSG_ALIGN(sizeof(Nlmsghdr))
+def NLMSG_LENGTH(len):
+    return len + NLMSG_ALIGN(NLMSG_HDRLEN())
+def NLMSG_SPACE(len):
+    return NLMSG_ALIGN(NLMSG_LENGTH(len))
+def NLMSG_DATA(nlh):
+    return addressof(nlh) + NLMSG_LENGTH(0)
+def NLMSG_NEXT(nlh, len):
+    cur = NLMSG_ALIGN(nlh.nlmsg_len)
+    nlh = Nlmsghdr.from_address(addressof(nlh) + cur)
+    return len - cur, nlh
+def NLMSG_OK(nlh, len):
+    return len >= sizeof(Nlmsghdr) and \
+        nlh.nlmsg_len >= sizeof(Nlmsghdr) and \
+        nlh.nlmsg_len <= len
+
+class Nlmsgerr(Structure):
+
+    _fields_ = [
+        ('error', c_int),
+        ('msg', Nlmsghdr),
+    ]
+
+class NetlinkError(Exception):
+
+    def __init__(self, message):
+        Exception.__init__(self, message)
+        #print(message)
+
+class Netlink(socket.socket):
+
+    def __init__(self, pid, proto):
+
+        self.pid = pid
+        self.recvbuf = bytearray(8 * 1024)
+        self.sendbuf = bytearray(8 * 1024)
+        self.seq = int(time())
+
+        try:
+
+            socket.socket.__init__(self, socket.AF_NETLINK, \
+                socket.SOCK_RAW, proto)
+            self.setblocking(0)
+
+            # Need to turn off ENOBUFS for netlink socket otherwise
+            # in a kernel overrun situation, the socket will return
+            # ENOBUFS on socket recv and be stuck for future recvs.
+
+            self.setsockopt(SOL_NETLINK, NETLINK_NO_ENOBUFS, 1)
+
+        except socket.error as (errno, string):
+            raise NetlinkError("open: socket err[%d]: %s" % \
+                (errno, string))
+
+    def bind(self, groups, cb):
+
+        self._nl_cb = cb
+
+        try:
+            socket.socket.bind(self, (self.pid, groups))
+
+        except socket.error as (errno, string):
+            raise NetlinkError("bind: socket err[%d]: %s" % \
+                (errno, string))
+
+    def sendall(self, string):
+        try:
+            socket.socket.sendall(self, string)
+        except socket.error as (errno, string):
+            raise NetlinkError("send: socket err[%d]: %s" % \
+                (errno, string))
+
+    def _process_nlh(self, recv, nlh):
+        while NLMSG_OK(nlh, recv):
+            yield recv, nlh
+            recv, nlh = NLMSG_NEXT(nlh, recv)
+
+    def process(self, tokens=[]):
+
+        found_done = False
+
+        try:
+            recv, src_addr = self.recvfrom_into(self.recvbuf)
+            if not recv:
+                # EOF
+                print "EOF"
+                return False
+
+        except socket.error as (errno, string):
+            if errno in [EINTR, EAGAIN]:
+                return False
+            raise NetlinkError("netlink: socket err[%d]: %s" % \
+                (errno, string))
+
+        nlh = Nlmsghdr.from_buffer(self.recvbuf)
+        for recv, nlh in self._process_nlh(recv, nlh):
+
+#            print "type %u, seq %u, pid %u" % \
+#                (nlh.nlmsg_type, nlh.nlmsg_seq, nlh.nlmsg_pid)
+
+            l = nlh.nlmsg_len - sizeof(Nlmsghdr)
+
+            if l < 0 or nlh.nlmsg_len > recv:
+                raise NetlinkError("netlink: malformed msg: len %d" % \
+                    nlh.nlmsg_len)
+
+            if tokens:
+                current = (nlh.nlmsg_pid, nlh.nlmsg_seq)
+                if current not in tokens:
+                    continue
+
+            if nlh.nlmsg_type == NLMSG_DONE:
+                found_done = True
+                break
+
+            if nlh.nlmsg_type == NLMSG_ERROR:
+                err = Nlmsgerr.from_address(NLMSG_DATA(nlh))
+                if err.error == 0:
+                    return False
+                raise NetlinkError("netlink: %s" % strerror(abs(err.error)))
+
+            if self._nl_cb:
+                self._nl_cb(nlh)
+
+        if found_done:
+            return False 
+
+        remnant = recv - NLMSG_ALIGN(nlh.nlmsg_len) > 0
+        if remnant:
+            raise NetlinkError("netlink: remnant of size %d" % \
+                remnant)
+
+        return True
+
+    def process_wait(self, tokens):
+        while self.process(tokens):
+            pass
+
+    def process_forever(self):
+        epoll = select.epoll()
+        epoll.register(self.fileno(), select.EPOLLIN)
+        while True:
+            events = epoll.poll()
+            for fileno, event in events:
+                if fileno == self.fileno():
+                    self.process()
+
+    def process_event(self, event):
+        return self.process()
diff --git a/ifupdown/networkinterfaces.py b/ifupdown/networkinterfaces.py
new file mode 100644 (file)
index 0000000..f241e45
--- /dev/null
@@ -0,0 +1,437 @@
+#!/usr/bin/python
+#
+# Copyright 2014 Cumulus Networks, Inc. All rights reserved.
+# Author: Roopa Prabhu, roopa@cumulusnetworks.com
+#
+# networkInterfaces --
+#    ifupdown network interfaces file parser
+#
+
+import collections
+import logging
+import glob
+import re
+import os
+import copy
+from utils import utils
+from iface import *
+from template import templateEngine
+
+whitespaces = '\n\t\r '
+
+class networkInterfaces():
+    """ debian ifupdown /etc/network/interfaces file parser """
+
+    hotplugs = {}
+    auto_ifaces = []
+    callbacks = {}
+    auto_all = False
+
+    _addrfams = {'inet' : ['static', 'manual', 'loopback', 'dhcp', 'dhcp6'],
+                 'inet6' : ['static', 'manual', 'loopback', 'dhcp', 'dhcp6']}
+
+    def __init__(self, interfacesfile='/etc/network/interfaces',
+                 interfacesfileiobuf=None, interfacesfileformat='native',
+                 template_engine=None, template_lookuppath=None):
+        """This member function initializes the networkinterfaces parser object.
+
+        Kwargs:
+            **interfacesfile** (str):  path to the interfaces file (default is /etc/network/interfaces)
+
+            **interfacesfileiobuf** (object): interfaces file io stream
+
+            **interfacesfileformat** (str): format of interfaces file (choices are 'native' and 'json'. 'native' being the default)
+
+            **template_engine** (str): template engine name
+
+            **template_lookuppath** (str): template lookup path
+
+        Raises:
+            AttributeError, KeyError """
+
+        self.logger = logging.getLogger('ifupdown.' +
+                    self.__class__.__name__)
+        self.callbacks = {'iface_found' : None,
+                          'validateifaceattr' : None,
+                          'validateifaceobj' : None}
+        self.allow_classes = {}
+        self.interfacesfile = interfacesfile
+        self.interfacesfileiobuf = interfacesfileiobuf
+        self.interfacesfileformat = interfacesfileformat
+        self._filestack = [self.interfacesfile]
+        self._template_engine = templateEngine(template_engine,
+                                    template_lookuppath)
+        self._currentfile_has_template = False
+        self._ws_split_regex = re.compile(r'[\s\t]\s*')
+
+    @property
+    def _currentfile(self):
+        try:
+            return self._filestack[-1]
+        except:
+            return self.interfacesfile
+
+    def _parse_error(self, filename, lineno, msg):
+        if lineno == -1 or self._currentfile_has_template:
+            self.logger.error('%s: %s' %(filename, msg))
+        else:
+            self.logger.error('%s: line%d: %s' %(filename, lineno, msg))
+
+    def _parse_warn(self, filename, lineno, msg):
+        if lineno == -1 or self._currentfile_has_template:
+            self.logger.warn('%s: %s' %(filename, msg))
+        else:
+            self.logger.warn('%s: line%d: %s' %(filename, lineno, msg))
+
+    def _validate_addr_family(self, ifaceobj, lineno=-1):
+        if ifaceobj.addr_family:
+            if not self._addrfams.get(ifaceobj.addr_family):
+                self._parse_error(self._currentfile, lineno,
+                    'iface %s: unsupported address family \'%s\''
+                    %(ifaceobj.name, ifaceobj.addr_family))
+                ifaceobj.addr_family = None
+                ifaceobj.addr_method = None
+                return
+            if ifaceobj.addr_method:
+                if (ifaceobj.addr_method not in
+                        self._addrfams.get(ifaceobj.addr_family)):
+                    self._parse_error(self._currentfile, lineno,
+                        'iface %s: unsupported address method \'%s\''
+                        %(ifaceobj.name, ifaceobj.addr_method))
+            else:
+                ifaceobj.addr_method = 'static'
+
+    def subscribe(self, callback_name, callback_func):
+        """This member function registers callback functions.
+
+        Args:
+            **callback_name** (str): callback function name (supported names: 'iface_found', 'validateifaceattr', 'validateifaceobj')
+
+            **callback_func** (function pointer): callback function pointer
+
+        Warns on error
+        """
+
+        if callback_name not in self.callbacks.keys():
+            print 'warning: invalid callback ' + callback_name
+            return -1
+
+        self.callbacks[callback_name] = callback_func
+
+    def ignore_line(self, line):
+        l = line.strip(whitespaces)
+        if not l or l[0] == '#':
+            return 1
+        return 0
+
+    def process_allow(self, lines, cur_idx, lineno):
+        allow_line = lines[cur_idx]
+
+        words = re.split(self._ws_split_regex, allow_line)
+        if len(words) <= 1:
+            raise Exception('invalid allow line \'%s\' at line %d'
+                            %(allow_line, lineno))
+
+        allow_class = words[0].split('-')[1]
+        ifacenames = words[1:]
+
+        if self.allow_classes.get(allow_class):
+            for i in ifacenames:
+                self.allow_classes[allow_class].append(i)
+        else:
+                self.allow_classes[allow_class] = ifacenames
+        return 0
+
+    def process_source(self, lines, cur_idx, lineno):
+        # Support regex
+        self.logger.debug('processing sourced line ..\'%s\'' %lines[cur_idx])
+        sourced_file = re.split(self._ws_split_regex, lines[cur_idx], 2)[1]
+        if sourced_file:
+            filenames = glob.glob(sourced_file)
+            if not filenames:
+                self._parse_warn(self._currentfile, lineno,
+                            'cannot find source file %s' %sourced_file)
+                return 0
+            for f in filenames:
+                self.read_file(f)
+        else:
+            self._parse_error(self._currentfile, lineno,
+                    'unable to read source line')
+        return 0
+
+    def process_auto(self, lines, cur_idx, lineno):
+        auto_ifaces = re.split(self._ws_split_regex, lines[cur_idx])[1:]
+        if not auto_ifaces:
+            self._parse_error(self._currentfile, lineno,
+                    'invalid auto line \'%s\''%lines[cur_idx])
+            return 0
+        for a in auto_ifaces:
+            if a == 'all':
+                self.auto_all = True
+                break
+            r = utils.parse_iface_range(a)
+            if r:
+                for i in range(r[1], r[2]):
+                   self.auto_ifaces.append('%s-%d' %(r[0], i))
+            self.auto_ifaces.append(a)
+        return 0
+
+    def _add_to_iface_config(self, ifacename, iface_config, attrname,
+                             attrval, lineno):
+        newattrname = attrname.replace("_", "-")
+        try:
+            if not self.callbacks.get('validateifaceattr')(newattrname,
+                                      attrval):
+                self._parse_error(self._currentfile, lineno,
+                        'iface %s: unsupported keyword (%s)'
+                        %(ifacename, attrname))
+                return
+        except:
+            pass
+        attrvallist = iface_config.get(newattrname, [])
+        if newattrname in ['scope', 'netmask', 'broadcast', 'preferred-lifetime']:
+            # For attributes that are related and that can have multiple
+            # entries, store them at the same index as their parent attribute.
+            # The example of such attributes is 'address' and its related
+            # attributes. since the related attributes can be optional, 
+            # we add null string '' in places where they are optional.
+            # XXX: this introduces awareness of attribute names in
+            # this class which is a violation.
+
+            # get the index corresponding to the 'address'
+            addrlist = iface_config.get('address')
+            if addrlist:
+                # find the index of last address element
+                for i in range(0, len(addrlist) - len(attrvallist) -1):
+                    attrvallist.append('')
+                attrvallist.append(attrval)
+                iface_config[newattrname] = attrvallist
+        elif not attrvallist:
+            iface_config[newattrname] = [attrval]
+        else:
+            iface_config[newattrname].append(attrval)
+
+    def parse_iface(self, lines, cur_idx, lineno, ifaceobj):
+        lines_consumed = 0
+        line_idx = cur_idx
+
+        iface_line = lines[cur_idx].strip(whitespaces)
+        iface_attrs = re.split(self._ws_split_regex, iface_line)
+        ifacename = iface_attrs[1]
+
+        # in cases where mako is unable to render the template
+        # or incorrectly renders it due to user template
+        # errors, we maybe left with interface names with
+        # mako variables in them. There is no easy way to
+        # recognize and warn about these. In the below check
+        # we try to warn the user of such cases by looking for
+        # variable patterns ('$') in interface names.
+        if '$' in ifacename:
+           self._parse_warn(self._currentfile, lineno,
+                    '%s: unexpected characters in interface name' %ifacename)
+
+        ifaceobj.raw_config.append(iface_line)
+        iface_config = collections.OrderedDict()
+        for line_idx in range(cur_idx + 1, len(lines)):
+            l = lines[line_idx].strip(whitespaces)
+            if self.ignore_line(l) == 1:
+                continue
+            attrs = re.split(self._ws_split_regex, l, 1)
+            if self._is_keyword(attrs[0]):
+                line_idx -= 1
+                break
+            # if not a keyword, every line must have at least a key and value
+            if len(attrs) < 2:
+                self._parse_error(self._currentfile, line_idx,
+                        'iface %s: invalid syntax \'%s\'' %(ifacename, l))
+                continue
+            ifaceobj.raw_config.append(l)
+            attrname = attrs[0]
+            # preprocess vars (XXX: only preprocesses $IFACE for now)
+            attrval = re.sub(r'\$IFACE', ifacename, attrs[1])
+            self._add_to_iface_config(ifacename, iface_config, attrname,
+                                      attrval, line_idx+1)
+        lines_consumed = line_idx - cur_idx
+
+        # Create iface object
+        if ifacename.find(':') != -1:
+            ifaceobj.name = ifacename.split(':')[0]
+        else:
+            ifaceobj.name = ifacename
+
+        ifaceobj.config = iface_config
+        ifaceobj.generate_env()
+
+        try:
+            ifaceobj.addr_family = iface_attrs[2]
+            ifaceobj.addr_method = iface_attrs[3]
+        except IndexError:
+            # ignore
+            pass
+        self._validate_addr_family(ifaceobj, lineno)
+
+        if self.auto_all or (ifaceobj.name in self.auto_ifaces):
+            ifaceobj.auto = True
+
+        classes = self.get_allow_classes_for_iface(ifaceobj.name)
+        if classes:
+            [ifaceobj.set_class(c) for c in classes]
+        
+        return lines_consumed       # Return next index
+
+    def process_iface(self, lines, cur_idx, lineno):
+        ifaceobj = iface()
+        lines_consumed = self.parse_iface(lines, cur_idx, lineno, ifaceobj)
+
+        range_val = utils.parse_iface_range(ifaceobj.name)
+        if range_val:
+           for v in range(range_val[1], range_val[2]):
+                ifaceobj_new = copy.deepcopy(ifaceobj)
+                ifaceobj_new.realname = '%s' %ifaceobj.name
+                ifaceobj_new.name = '%s%d' %(range_val[0], v)
+                ifaceobj_new.flags = iface.IFACERANGE_ENTRY
+                if v == range_val[1]:
+                    ifaceobj_new.flags |= iface.IFACERANGE_START
+                self.callbacks.get('iface_found')(ifaceobj_new)
+        else:
+            self.callbacks.get('iface_found')(ifaceobj)
+
+        return lines_consumed       # Return next index
+
+    def process_vlan(self, lines, cur_idx, lineno):
+        ifaceobj = iface()
+        lines_consumed = self.parse_iface(lines, cur_idx, lineno, ifaceobj)
+
+        range_val = utils.parse_iface_range(ifaceobj.name)
+        if range_val:
+           for v in range(range_val[1], range_val[2]):
+                ifaceobj_new = copy.deepcopy(ifaceobj)
+                ifaceobj_new.realname = '%s' %ifaceobj.name
+                ifaceobj_new.name = '%s%d' %(range_val[0], v)
+                ifaceobj_new.type = ifaceType.BRIDGE_VLAN
+                ifaceobj_new.flags = iface.IFACERANGE_ENTRY
+                if v == range_val[1]:
+                    ifaceobj_new.flags |= iface.IFACERANGE_START
+                self.callbacks.get('iface_found')(ifaceobj_new)
+        else:
+            ifaceobj.type = ifaceType.BRIDGE_VLAN
+            self.callbacks.get('iface_found')(ifaceobj)
+
+        return lines_consumed       # Return next index
+
+    network_elems = { 'source'      : process_source,
+                      'allow'      : process_allow,
+                      'auto'        : process_auto,
+                      'iface'       : process_iface,
+                      'vlan'       : process_vlan}
+
+    def _is_keyword(self, str):
+        # The additional split here is for allow- keyword
+        tmp_str = str.split('-')[0]
+        if tmp_str in self.network_elems.keys():
+            return 1
+        return 0
+
+    def _get_keyword_func(self, str):
+        tmp_str = str.split('-')[0]
+        return self.network_elems.get(tmp_str)
+
+    def get_allow_classes_for_iface(self, ifacename):
+        classes = []
+        for class_name, ifacenames in self.allow_classes.items():
+            if ifacename in ifacenames:
+                classes.append(class_name)
+        return classes
+
+    def process_interfaces(self, filedata):
+
+        # process line continuations
+        filedata = ' '.join(d.strip() for d in filedata.split('\\'))
+
+        line_idx = 0
+        lines_consumed = 0
+        raw_config = filedata.split('\n')
+        lines = [l.strip(whitespaces) for l in raw_config]
+        while (line_idx < len(lines)):
+            if self.ignore_line(lines[line_idx]):
+                line_idx += 1
+                continue
+            words = re.split(self._ws_split_regex, lines[line_idx])
+            if not words:
+                line_idx += 1
+                continue
+            # Check if first element is a supported keyword
+            if self._is_keyword(words[0]):
+                keyword_func = self._get_keyword_func(words[0])
+                lines_consumed = keyword_func(self, lines, line_idx, line_idx+1)
+                line_idx += lines_consumed
+            else:
+                self._parse_error(self._currentfile, line_idx + 1,
+                        'error processing line \'%s\'' %lines[line_idx])
+            line_idx += 1
+        return 0
+
+    def read_filedata(self, filedata):
+        self._currentfile_has_template = False
+        # run through template engine
+        try:
+            rendered_filedata = self._template_engine.render(filedata)
+            if rendered_filedata is filedata:
+                self._currentfile_has_template = False
+            else:
+                self._currentfile_has_template = True
+        except Exception, e:
+            self._parse_error(self._currentfile, -1,
+                    'failed to render template (%s). ' %str(e) +
+                    'Continue without template rendering ...')
+            rendered_filedata = None
+            pass
+        if rendered_filedata:
+            self.process_interfaces(rendered_filedata)
+        else:
+            self.process_interfaces(filedata)
+
+    def read_file(self, filename, fileiobuf=None):
+        if fileiobuf:
+            self.read_filedata(fileiobuf)
+            return
+        self._filestack.append(filename)
+        self.logger.info('processing interfaces file %s' %filename)
+        f = open(filename)
+        filedata = f.read()
+        f.close()
+        self.read_filedata(filedata)
+        self._filestack.pop()
+
+    def read_file_json(self, filename, fileiobuf=None):
+        if fileiobuf:
+            ifacedicts = json.loads(fileiobuf, encoding="utf-8")
+                              #object_hook=ifaceJsonDecoder.json_object_hook)
+        elif filename:
+            self.logger.info('processing interfaces file %s' %filename)
+            fp = open(filename)
+            ifacedicts = json.load(fp)
+                            #object_hook=ifaceJsonDecoder.json_object_hook)
+
+        # we need to handle both lists and non lists formats (e.g. {{}})
+        if not isinstance(ifacedicts,list):
+            ifacedicts = [ifacedicts]
+
+        for ifacedict in ifacedicts:
+            ifaceobj = ifaceJsonDecoder.json_to_ifaceobj(ifacedict)
+            if ifaceobj:
+                self._validate_addr_family(ifaceobj)
+                self.callbacks.get('validateifaceobj')(ifaceobj)
+                self.callbacks.get('iface_found')(ifaceobj)
+        
+    def load(self):
+        """ This member function loads the networkinterfaces file.
+
+        Assumes networkinterfaces parser object is initialized with the
+        parser arguments
+        """
+        if self.interfacesfileformat == 'json':
+            return self.read_file_json(self.interfacesfile,
+                                       self.interfacesfileiobuf)
+        return self.read_file(self.interfacesfile,
+                              self.interfacesfileiobuf)
diff --git a/ifupdown/policymanager.py b/ifupdown/policymanager.py
new file mode 100644 (file)
index 0000000..2f9cbac
--- /dev/null
@@ -0,0 +1,175 @@
+#!/usr/bin/python
+#
+# Copyright 2015 Cumulus Networks, Inc. All rights reserved.
+#
+#
+'''
+The PolicyManager should be subclassed by addon modules
+to read a JSON policy config file that is later used to
+set defaults:
+
+Initialize: This module defines a list of config file location based
+          on module.  There are defined in the __init__():  All the
+          addon modules need to do is import the policymanager module.
+
+          import ifupdown.policymanager as policymanager
+
+
+Provides: an API to retrieve link attributes based on addon module name,
+          interface name, and attribute.
+
+        The ifupdown.policymanager module provides a global object policymanager_api
+        that can be called like so:
+
+        speed_default = policymanager.policymanager_api.get_default(
+            module_name='ethtool',
+            ifname=ifaceobj.name,
+            attr='link-speed'
+            )
+'''
+
+import json
+import logging
+import glob
+
+class policymanager():
+    def __init__(self):
+        # we should check for these files in order
+        # so that customers can override the /var/lib file settings
+        self.logger = logging.getLogger('ifupdown.' +
+                            self.__class__.__name__)
+
+        # we grab the json files from a known location and make sure that
+        # the defaults_policy is checked first
+        user_files = glob.glob('/etc/network/ifupdown2/policy.d/*.json')
+        # grab the default module files
+        default_files = glob.glob('/var/lib/ifupdownaddons/policy.d/*.json')
+        # keep an array of defaults indexed by module name
+        self.system_policy_array = {}
+        for filename in default_files:
+            system_array  = {}
+            try:
+                fd = open(filename,'r')
+                system_array = json.load(fd)
+                self.logger.debug('reading %s system policy defaults config' \
+                                  % filename)
+            except Exception, e:
+                self.logger.debug('could not read %s system policy defaults config' \
+                                  % filename)
+                self.logger.debug('    exception is %s' % str(e))
+            for module in system_array.keys():
+                if self.system_policy_array.has_key(module):
+                    self.logger.debug('warning: overwriting system module %s from file %s' \
+                                      % (module,filename))
+                self.system_policy_array[module] = system_array[module]
+
+        # take care of user defined policy defaults
+        self.user_policy_array = {}
+        for filename in user_files:
+            user_array  = {}
+            try:
+                fd = open(filename,'r')
+                user_array = json.load(fd)
+                self.logger.debug('reading %s policy user defaults config' \
+                                  % filename)
+            except Exception, e:
+                self.logger.debug('could not read %s user policy defaults config' \
+                                  % filename)
+                self.logger.debug('    exception is %s' % str(e))
+            # customer added module attributes
+            for module in user_array.keys():
+                if self.system_policy_array.has_key(module):
+                    # warn user that we are overriding the system module setting
+                    self.logger.debug('warning: overwriting system with user module %s from file %s' \
+                                      % (module,filename))
+                self.user_policy_array[module] = user_array[module]
+        return
+
+    def get_iface_default(self,module_name=None,ifname=None,attr=None):
+        '''
+        get_iface_default: Addon modules must use one of two types of access methods to
+        the default configs.   In this method, we expect the default to be
+        either in
+            [module]['iface_defaults'][ifname][attr] or
+            [module]['defaults'][attr]
+        We first check the user_policy_array and return that value. But if
+        the user did not specify an override, we use the system_policy_array.
+        '''
+        # make sure we have an index
+        if (not ifname or not attr or not module_name):
+            return None
+
+        val = None
+        # users can specify defaults to override the systemwide settings
+        # look for user specific interface attribute iface_defaults first
+        try:
+            # looks for user specified value
+            val = self.user_policy_array[module_name]['iface_defaults'][ifname][attr]
+            return val
+        except:
+            pass
+        try:
+            # failing that, there may be a user default for all intefaces
+            val = self.user_policy_array[module_name]['defaults'][attr]
+            return val
+        except:
+            pass
+        try:
+            # failing that, look for  system setting for the interface
+            val = self.system_policy_array[module_name]['iface_defaults'][ifname][attr]
+            return val
+        except:
+            pass
+        try:
+            # failing that, look for  system setting for all interfaces
+            val = self.system_policy_array[module_name]['defaults'][attr]
+            return val
+        except:
+            pass
+
+        # could not find any system or user default so return Non
+        return val
+
+    def get_attr_default(self,module_name=None,attr=None):
+        '''
+        get_attr_default: Addon modules must use one of two types of access methods to
+        the default configs.   In this method, we expect the default to be in
+
+        [module][attr] 
+
+        We first check the user_policy_array and return that value. But if
+        the user did not specify an override, we use the system_policy_array.
+        '''
+        if (not attr or not module_name):
+            return None
+        # users can specify defaults to override the systemwide settings
+        # look for user specific interface attribute iface_defaults first
+        val = None
+        if self.user_policy_array.get(module_name):
+            val = self.user_policy_array[module_name].get(attr)
+
+        if not val:
+            if self.system_policy_array.get(module_name):
+                val = self.system_policy_array[module_name].get(attr)
+
+        return val
+
+    def get_module_default(self,module_name=None):
+        '''
+        get_module_default: Addon modules can also access the entire config
+        This method returns indexed by "system" and "user": these are the
+        system-wide and user-defined policy arrays for a specific module.
+        '''
+        if not module_name:
+            return None
+        if self.system_policy_array.get(module_name) and \
+           self.user_policy_array.get(module_name):
+            mod_array = {"system":self.system_policy_array[module_name],
+                         "user":self.user_policy_array[module_name]}
+        else:
+            # the module must not have these defined, return None
+            mod_array = None
+
+        return mod_array
+
+policymanager_api = policymanager()
diff --git a/ifupdown/rtnetlink.py b/ifupdown/rtnetlink.py
new file mode 100644 (file)
index 0000000..9b13ad5
--- /dev/null
@@ -0,0 +1,860 @@
+#!/usr/bin/env python
+#
+# Copyright 2014 Cumulus Networks, Inc. All rights reserved.
+#
+# Author: Scott Feldman, sfeldma@cumulusnetworks.com
+# Author: Roopa Prabhu, roopa@cumulusnetworks.com
+#
+#
+from socket import NETLINK_ROUTE, AF_INET, AF_INET6
+from string import printable
+from ipaddr import *
+from ctypes import *
+from netlink import *
+import logging
+
+logger = logging.getLogger(__name__)
+
+#
+# from /usr/include/linux/rtnetlink.h
+#
+
+RTMGRP_LINK = 0x1
+RTMGRP_IPV4_IFADDR = 0x10
+RTMGRP_IPV4_ROUTE = 0x40
+RTMGRP_IPV6_IFADDR = 0x100
+RTMGRP_IPV6_ROUTE = 0x400
+
+RTM_NEWLINK = 16
+RTM_DELLINK = 17
+RTM_GETLINK = 18
+RTM_SETLINK = 19
+RTM_NEWADDR = 20
+RTM_DELADDR = 21
+RTM_GETADDR = 22
+RTM_NEWROUTE = 24
+RTM_DELROUTE = 25
+RTM_GETROUTE = 26
+
+# Definitions used in routing table administration.
+
+class Nlmsg(Structure):
+
+    def _stringify(self):
+        return string_at(addressof(self), sizeof(self))
+
+    def __eq__(self, other):
+        return self._stringify() == other._stringify() and \
+            self.__dict__ == other.__dict__
+
+    def to_rta(self):
+        return Rtattr.from_address(addressof(self) + NLMSG_ALIGN(sizeof(self)))
+
+    def pack_extra(self, extra, addr):
+        memmove(addr, addressof(extra), sizeof(extra))
+        return NLMSG_ALIGN(sizeof(extra))
+
+    def pack_rtas(self, rtas, addr):
+        total_len = 0
+        for rta_type, value in rtas.iteritems():
+            rta = Rtattr.from_address(addr)
+            rta.rta_type = rta_type
+            pack_fn = self.rta_fn(rta_type)
+            rta_len = NLMSG_ALIGN(pack_fn(rta, value))
+            total_len += rta_len
+            addr += rta_len
+        return total_len
+
+    def pack_rtas_new(self, rtas, addr, policy):
+        total_len = 0
+                
+        for rta_type, value in rtas.iteritems():
+            if type(value) == dict:
+               rta = Rtattr.from_address(addr)
+               rta.rta_type = rta_type
+                rta.rta_len = RTA_LENGTH(0)
+                rta_len = NLMSG_ALIGN(rta.rta_len)
+                total_len += rta_len
+                addr += rta_len
+               pack_fn = policy.get(rta_type)
+                rta_len = NLMSG_ALIGN(pack_fn(addr, value))
+
+                rta.rta_len += rta_len
+            else:
+                rta = Rtattr.from_address(addr)
+                rta.rta_type = rta_type
+                pack_fn = policy.get(rta_type)
+                rta_len = NLMSG_ALIGN(pack_fn(rta, value))
+            total_len += rta_len
+            addr += rta_len
+        return total_len
+
+    def rta_linkinfo(self, addr, rtas):
+        total_len = 0
+
+        # Check interface kind 
+        kind = rtas.get(IFLA_INFO_KIND)
+        if kind == 'vlan':
+            data_policy = self.rta_linkinfo_data_vlan_policy()
+        else:
+            data_policy = self.rta_linkinfo_data_macvlan_policy()
+
+        # Pack info kind
+        rta = Rtattr.from_address(addr)
+        rta.rta_type = IFLA_INFO_KIND
+        rta_len = NLMSG_ALIGN(self.rta_string(rta, kind))
+        total_len += rta_len
+        addr += rta_len
+
+        # nest start link info data
+        rta = Rtattr.from_address(addr)
+        rta.rta_type = IFLA_INFO_DATA
+        rta.rta_len = RTA_LENGTH(0)
+        rta_len = NLMSG_ALIGN(rta.rta_len)
+        total_len += rta_len
+        addr += rta_len
+        rta_len = self.pack_rtas_new(rtas.get(IFLA_INFO_DATA), addr,
+                                     data_policy)
+        rta.rta_len += rta_len
+
+        total_len += rta_len
+        addr += rta_len
+
+        return total_len
+
+    def rta_bridge_vlan_info(self, rta, value):
+        if value:
+           data = RTA_DATA(rta)
+           memmove(data, addressof(value), sizeof(value))
+           rta.rta_len = RTA_LENGTH(sizeof(value))
+           return rta.rta_len
+
+    def rta_af_spec(self, addr, rtas):
+        total_len = 0
+
+        # XXX: Check family (Assumes bridge family for now)
+        rta_len = self.pack_rtas_new(rtas, addr,
+                                     self.rta_bridge_af_spec_policy())
+        total_len += rta_len
+        return total_len
+
+    def unpack_rtas(self, which_ones=[]):
+        len = self.nlh.nlmsg_len - NLMSG_LENGTH(sizeof(self))
+        rta = self.to_rta()
+        rtas = {}
+        while RTA_OK(rta, len):
+            rta_type = rta.rta_type
+            if not which_ones or rta_type in which_ones:
+                unpack_fn = self.rta_fn(rta_type)
+                rtas[rta_type] = unpack_fn(rta)
+            len, rta = RTA_NEXT(rta, len)
+        return rtas
+
+    def dump_rtas(self):
+        rtas = self.unpack_rtas()
+        for type, value in rtas.iteritems():
+            print "rta", type, ":", value
+
+    class _IPv6Addr(BigEndianStructure):
+        _fields_ = [
+            ('upper', c_uint64),
+            ('lower', c_uint64),
+        ]
+
+    class _IPv4Addr(BigEndianStructure):
+        _fields_ = [
+            ('addr', c_uint32),
+        ]
+
+    def rta_uint8(self, rta, value=None):
+        data = RTA_DATA(rta)
+        if value:
+            c_uint8.from_address(data).value = value
+            rta.rta_len = RTA_LENGTH(sizeof(c_uint8))
+            return rta.rta_len
+       else:
+            return c_uint8.from_address(data).value
+
+    def rta_uint16(self, rta, value=None):
+        data = RTA_DATA(rta)
+        if value:
+            c_uint16.from_address(data).value = value
+            rta.rta_len = RTA_LENGTH(sizeof(c_uint16))
+            return rta.rta_len
+       else:
+            return c_uint16.from_address(data).value
+
+    def rta_uint32(self, rta, value=None):
+        data = RTA_DATA(rta)
+        if value:
+            c_uint32.from_address(data).value = value
+            rta.rta_len = RTA_LENGTH(sizeof(c_uint32))
+            return rta.rta_len
+        else:
+            return c_uint32.from_address(data).value
+
+    def rta_string(self, rta, value=None):
+        data = RTA_DATA(rta)
+        if value:
+            s = create_string_buffer(value)
+            memmove(data, addressof(s), len(value))
+            rta.rta_len = RTA_LENGTH(len(value))
+            return rta.rta_len
+        else:
+            return c_char_p(data).value
+
+    def rta_addr(self, rta, value=None):
+        data = RTA_DATA(rta)
+        if value:
+            if isinstance(value, IPv4Address):
+                self._IPv4Addr.from_address(data).addr = value._ip
+                rta.rta_len = RTA_LENGTH(sizeof(self._IPv4Addr))
+            elif isinstance(value, IPv6Address):
+                addr = self._IPv6Addr.from_address(data)
+                addr.upper = value._ip >> 64
+                addr.lower = value._ip & 0xffffffffffffffff
+                rta.rta_len = RTA_LENGTH(sizeof(self._IPv6Addr))
+            else:
+                assert(False)
+            return rta.rta_len
+        else:
+            if RTA_PAYLOAD(rta) == 4:
+                addr = c_uint32.__ctype_be__.from_address(data).value
+                addr = IPv4Address(addr)
+            else:
+                addr = self._IPv6Addr.from_address(data)
+                addr = IPv6Address((addr.upper << 64) + addr.lower)
+            return addr
+
+    def rta_uint8_array(self, rta, value=None):
+        data = RTA_DATA(rta)
+        if value:
+            s = (c_uint8 * len(value)).from_buffer_copy(value)
+            memmove(data, addressof(s), len(value))
+            rta.rta_len = RTA_LENGTH(len(value))
+            return rta.rta_len
+        else:
+            array = (c_uint8 * RTA_PAYLOAD(rta))()
+            memmove(array, data, RTA_PAYLOAD(rta))
+            return array
+
+    def rta_uint32_array(self, rta, value=None):
+        if value:
+            assert(False)
+        else:
+            data = RTA_DATA(rta)
+            size = RTA_PAYLOAD(rta) / sizeof(c_uint32)
+            array = (c_uint32 * size)()
+            memmove(array, data, RTA_PAYLOAD(rta))
+            return array
+
+    def rta_multipath(self, rta, value=None):
+        # XXX implement this
+        return None
+
+    def rta_wtf(self, rta, value=None):
+        return None
+
+    def rta_none(self, rta, value=None):
+        return None
+
+    def rta_fn(self, rta_type):
+        return None
+
+
+# rtm_type
+
+RTN_UNSPEC = 0
+RTN_UNICAST = 1            # Gateway or direct route
+RTN_LOCAL = 2              # Accept locally
+RTN_BROADCAST = 3          # Accept locally as broadcast,
+                           # send as broadcast
+RTN_ANYCAST = 4            # Accept locally as broadcast,
+                           # but send as unicast
+RTN_MULTICAST = 5          # Multicast route
+RTN_BLACKHOLE = 6          # Drop
+RTN_UNREACHABLE = 7        # Destination is unreachable
+RTN_PROHIBIT = 8           # Administratively prohibited
+RTN_THROW = 9              # Not in this table
+RTN_NAT = 10               # Translate this address
+RTN_XRESOLVE = 11          # Use external resolver
+RTN_MAX = 11
+
+# rtm_protocol
+
+RTPROT_UNSPEC = 0
+RTPROT_REDIRECT = 1     # Route installed by ICMP redirects;
+                        # not used by current IPv4
+RTPROT_KERNEL = 2       # Route installed by kernel
+RTPROT_BOOT = 3         # Route installed during boot
+RTPROT_STATIC = 4       # Route installed by administrator
+
+# Values of protocol >= RTPROT_STATIC are not interpreted by kernel;
+# they are just passed from user and back as is.
+# It will be used by hypothetical multiple routing daemons.
+# Note that protocol values should be standardized in order to
+# avoid conflicts.
+
+RTPROT_GATED = 8       # Apparently, GateD
+RTPROT_RA = 9          # RDISC/ND router advertisements
+RTPROT_MRT = 10        # Merit MRT
+RTPROT_ZEBRA = 11      # Zebra
+RTPROT_BIRD = 12       # BIRD
+RTPROT_DNROUTED = 13   # DECnet routing daemon
+RTPROT_XORP = 14       # XORP
+RTPROT_NTK = 15        # Netsukuku
+RTPROT_DHCP = 16       # DHCP client
+
+# rtm_scope
+
+# Really it is not scope, but sort of distance to the destination.
+# NOWHERE are reserved for not existing destinations, HOST is our
+# local addresses, LINK are destinations, located on directly attached
+# link and UNIVERSE is everywhere in the Universe.
+
+# Intermediate values are also possible f.e. interior routes
+# could be assigned a value between UNIVERSE and LINK.
+
+RT_SCOPE_UNIVERSE = 0
+# User defined values
+RT_SCOPE_SITE = 200
+RT_SCOPE_LINK = 253
+RT_SCOPE_HOST = 254
+RT_SCOPE_NOWHERE=255
+
+# rtm_flags
+
+RTM_F_NOTIFY = 0x100   # Notify user of route change
+RTM_F_CLONED = 0x200   # This route is cloned
+RTM_F_EQUALIZE = 0x400 # Multipath equalizer: NI
+RTM_F_PREFIX = 0x800   # Prefix addresses
+
+# Reserved table identifiers
+
+RT_TABLE_UNSPEC = 0
+# User defined values
+RT_TABLE_COMPAT = 252
+RT_TABLE_DEFAULT = 253
+RT_TABLE_MAIN = 254
+RT_TABLE_LOCAL = 255
+RT_TABLE_MAX = 0xFFFFFFFF
+
+# Generic structure for encapsulation of optional route information.
+# It is reminiscent of sockaddr, but with sa_family replaced
+# with attribute type.
+
+class Rtattr(Structure):
+
+    _fields_ = [
+        ('rta_len', c_uint16),
+        ('rta_type', c_uint16),
+    ]
+
+# Routing message attributes
+
+RTA_UNSPEC = 0
+RTA_DST = 1
+RTA_SRC = 2
+RTA_IIF = 3
+RTA_OIF = 4
+RTA_GATEWAY = 5
+RTA_PRIORITY = 6
+RTA_PREFSRC = 7
+RTA_METRICS = 8
+RTA_MULTIPATH = 9
+RTA_PROTOINFO = 10        # no longer used
+RTA_FLOW = 11
+RTA_CACHEINFO = 12
+RTA_SESSION = 13          # no longer used
+RTA_MP_ALGO = 14          # no longer used 
+RTA_TABLE = 15
+RTA_MAX = 15
+
+# Macros to handle rtattributes
+
+RTA_ALIGNTO = 4
+def RTA_ALIGN(len):
+    return (len + RTA_ALIGNTO - 1) & ~(RTA_ALIGNTO - 1)
+def RTA_OK(rta, len):
+    return len >= sizeof(Rtattr) and \
+        rta.rta_len >= sizeof(Rtattr) and \
+        rta.rta_len <= len
+def RTA_NEXT(rta, len):
+    cur = RTA_ALIGN(rta.rta_len)
+    rta = Rtattr.from_address(addressof(rta) + cur)
+    return len - cur, rta
+def RTA_LENGTH(len):
+    return len + RTA_ALIGN(sizeof(Rtattr))
+def RTA_SPACE(len):
+    return RTA_ALIGN(RTA_LENGTH(len))
+def RTA_DATA(rta):
+    return addressof(rta) + RTA_LENGTH(0)
+def RTA_PAYLOAD(rta):
+    return rta.rta_len - RTA_LENGTH(0)
+
+RTNH_F_DEAD = 1         # Nexthop is dead (used by multipath)
+RTNH_F_PERVASIVE = 2    # Do recursive gateway lookup
+RTNH_F_ONLINK = 4       # Gateway is forced on link
+
+# Reserved table identifiers
+
+RT_TABLE_UNSPEC = 0
+# User defined values
+RT_TABLE_COMPAT = 252
+RT_TABLE_DEFAULT = 253
+RT_TABLE_MAIN = 254
+RT_TABLE_LOCAL = 255
+RT_TABLE_MAX = 0xFFFFFFFF
+
+class Rtmsg(Nlmsg):
+
+    _fields_ = [
+        ('rtm_family', c_uint8),
+        ('rtm_dst_len', c_uint8),
+        ('rtm_src_len', c_uint8),
+        ('rtm_tos', c_uint8),
+        ('rtm_table', c_uint8),
+        ('rtm_protocol', c_uint8),
+        ('rtm_scope', c_uint8),
+        ('rtm_type', c_uint8),
+        ('rtm_flags', c_uint32),
+    ]
+
+    _table_str = {
+        RT_TABLE_UNSPEC: "unspecified",
+        RT_TABLE_COMPAT: "compat",
+        RT_TABLE_DEFAULT: "default",
+        RT_TABLE_MAIN: "main",
+        RT_TABLE_LOCAL: "local",
+    }
+
+    _proto_str = {
+        RTPROT_UNSPEC: "none",
+        RTPROT_REDIRECT: "redirect",
+        RTPROT_KERNEL: "kernel",
+        RTPROT_BOOT: "boot",
+        RTPROT_STATIC: "static",
+        RTPROT_GATED: "gated",
+        RTPROT_RA: "ra",
+        RTPROT_MRT: "mrtmrt",
+        RTPROT_ZEBRA: "zebra",
+        RTPROT_BIRD: "bird",
+        RTPROT_DNROUTED: "dnrouted",
+        RTPROT_XORP: "xorp",
+        RTPROT_NTK: "ntk",
+        RTPROT_DHCP: "dhcp",
+    }
+
+    _scope_str = {
+        RT_SCOPE_UNIVERSE: "universe",
+        RT_SCOPE_SITE: "site",
+        RT_SCOPE_LINK: "link",
+        RT_SCOPE_HOST: "host",
+        RT_SCOPE_NOWHERE: "nowhere",
+    }
+
+    _type_str = {
+        RTN_UNSPEC: "unspecified",
+        RTN_UNICAST: "unicast",
+        RTN_LOCAL: "local",
+        RTN_BROADCAST: "broadcast",
+        RTN_ANYCAST: "anycast",
+        RTN_MULTICAST: "multicast",
+        RTN_BLACKHOLE: "blackhole",
+        RTN_UNREACHABLE: "unreachable",
+        RTN_PROHIBIT: "prohibit",
+        RTN_THROW: "throw",
+        RTN_NAT: "nat",
+        RTN_XRESOLVE: "xresolve",
+    }
+
+    def dump(self):
+        print 'rtm_family', self.rtm_family
+        print 'rtm_dst_len', self.rtm_dst_len
+        print 'rtm_src_len', self.rtm_src_len
+        print 'rtm_tos', self.rtm_tos
+        print 'rtm_table', self._table_str.get(self.rtm_table, self.rtm_table)
+        print 'rtm_protocol', self._proto_str.get(self.rtm_protocol)
+        print 'rtm_scope', self._scope_str.get(self.rtm_scope)
+        print 'rtm_type', self._type_str.get(self.rtm_type)
+        print 'rtm_flags 0x%08x' % self.rtm_flags
+
+    def rta_fn(self, rta_type):
+        fns = {
+            RTA_DST: self.rta_addr,
+            RTA_SRC: self.rta_addr,
+            RTA_IIF: self.rta_uint32,
+            RTA_OIF: self.rta_uint32,
+            RTA_GATEWAY: self.rta_addr,
+            RTA_PRIORITY: self.rta_uint32,
+            RTA_PREFSRC: self.rta_addr,
+            RTA_METRICS: self.rta_uint32_array,
+            RTA_MULTIPATH: self.rta_multipath,
+            RTA_PROTOINFO: self.rta_none,
+            RTA_FLOW: self.rta_uint32,
+            RTA_CACHEINFO: self.rta_none,
+            RTA_SESSION: self.rta_none,
+            RTA_MP_ALGO: self.rta_none,
+            RTA_TABLE: self.rta_uint32,
+        }
+
+        return fns.get(rta_type)
+
+class Rtgenmsg(Nlmsg):
+
+    _fields_ = [
+        ('rtgen_family', c_uint8),
+    ]
+
+    def dump(self):
+        print 'rtgen_family', self.rtgen_family
+
+# New extended info filters for IFLA_EXT_MASK
+RTEXT_FILTER_VF = (1 << 0)
+
+# passes link level specific information, not dependent
+# on network protocol.
+
+IFLA_UNSPEC = 0
+IFLA_ADDRESS = 1
+IFLA_BROADCAST = 2
+IFLA_IFNAME = 3
+IFLA_MTU = 4
+IFLA_LINK = 5
+IFLA_QDISC = 6
+IFLA_STATS = 7
+IFLA_COST = 8
+IFLA_PRIORITY = 9
+IFLA_MASTER = 10
+IFLA_WIRELESS = 11          # Wireless Extension event - see wireless.h
+IFLA_PROTINFO = 12          # Protocol specific information for a link
+IFLA_TXQLEN = 13
+IFLA_MAP = 14
+IFLA_WEIGHT = 15
+IFLA_OPERSTATE = 16
+IFLA_LINKMODE = 17
+IFLA_LINKINFO = 18
+IFLA_NET_NS_PID = 19
+IFLA_IFALIAS = 20
+IFLA_NUM_VF = 21            # Number of VFs if device is SR-IOV PF
+IFLA_VFINFO_LIST = 22
+IFLA_STATS64 = 23
+IFLA_VF_PORTS = 24
+IFLA_PORT_SELF = 25
+IFLA_AF_SPEC = 26
+IFLA_GROUP = 27             # Group the device belongs to
+IFLA_NET_NS_FD = 28
+IFLA_EXT_MASK = 29          # Extended info mask, VFs, etc
+IFLA_MAX = 29
+
+
+# IFLA_LINKINFO attributes
+IFLA_INFO_UNSPEC = 0
+IFLA_INFO_KIND = 1
+IFLA_INFO_DATA = 2
+IFLA_INFO_XSTATS = 3
+IFLA_INFO_MAX = 4
+
+# IFLA_LINKINFO_DATA attributes for vlan
+IFLA_VLAN_UNSPEC = 0
+IFLA_VLAN_ID = 1
+
+# IFLA_LINKINFO_DATA attributes for macvlan
+IFLA_MACVLAN_UNSPEC = 0
+IFLA_MACVLAN_MODE = 1
+
+# macvlan modes
+MACVLAN_MODE_PRIVATE = 1
+MACVLAN_MODE_VEPA = 2
+MACVLAN_MODE_BRIDGE = 3
+MACVLAN_MODE_PASSTHRU = 4
+
+# BRIDGE IFLA_AF_SPEC attributes
+IFLA_BRIDGE_FLAGS = 0
+IFLA_BRIDGE_MODE = 1
+IFLA_BRIDGE_VLAN_INFO = 2
+
+# BRIDGE_VLAN_INFO flags
+BRIDGE_VLAN_INFO_MASTER = 1
+BRIDGE_VLAN_INFO_PVID = 2
+BRIDGE_VLAN_INFO_UNTAGGED = 4
+
+# Bridge flags
+BRIDGE_FLAGS_MASTER = 1
+BRIDGE_FLAGS_SELF = 2
+
+class BridgeVlanInfo(Structure):
+    _fields_ = [
+        ('flags', c_uint16),
+        ('vid', c_uint16),
+        ('vid_end', c_uint16),
+    ]
+
+class Ifinfomsg(Nlmsg):
+
+    _fields_ = [
+        ('ifi_family', c_uint8),
+        ('__ifi_pad', c_uint8),
+        ('ifi_type', c_uint16),      # ARPHRD_*
+        ('ifi_index', c_int32),      # Link index
+        ('ifi_flags', c_uint32),     # IFF_* flags
+        ('ifi_change', c_uint32),    # IFF_* change mask
+    ]
+
+    def dump(self):
+        print 'ifi_family', self.ifi_family
+        print 'ifi_type', self.ifi_type
+        print 'ifi_index', self.ifi_index
+        print 'ifi_flags 0x%08x' % self.ifi_flags
+        print 'ifi_change 0x%08x' % self.ifi_change
+
+    def rta_linkinfo_data_vlan_policy(self):
+        fns = {
+            IFLA_VLAN_ID : self.rta_uint16,
+        }
+        return fns
+
+    def rta_linkinfo_data_macvlan_policy(self):
+        fns = {
+            IFLA_MACVLAN_MODE : self.rta_uint32,
+        }
+        return fns
+
+    def rta_linkinfo_policy(self):
+        fns = {
+            IFLA_INFO_KIND : self.rta_string,
+            IFLA_INFO_DATA : self.rta_linkinfo_data,
+        }
+        return fns
+
+    def rta_bridge_af_spec_policy(self):
+        # Assume bridge family for now
+        fns = {
+            IFLA_BRIDGE_FLAGS : self.rta_uint16,
+            IFLA_BRIDGE_VLAN_INFO : self.rta_bridge_vlan_info,
+        }
+        return fns
+
+    def rta_policy(self):
+        fns = {
+            IFLA_UNSPEC: self.rta_wtf,
+            IFLA_ADDRESS: self.rta_uint8_array,
+            IFLA_BROADCAST: self.rta_uint8_array,
+            IFLA_IFNAME: self.rta_string,
+            IFLA_MTU: self.rta_uint32,
+            IFLA_LINK: self.rta_uint32,
+            IFLA_QDISC: self.rta_string,
+            IFLA_STATS: self.rta_none,
+            IFLA_COST: self.rta_none,
+            IFLA_PRIORITY: self.rta_none,
+            IFLA_MASTER: self.rta_uint32,
+            IFLA_WIRELESS: self.rta_none,
+            IFLA_PROTINFO: self.rta_none,
+            IFLA_TXQLEN: self.rta_uint32,
+            IFLA_MAP: self.rta_none,
+            IFLA_WEIGHT: self.rta_uint32,
+            IFLA_OPERSTATE: self.rta_uint8,
+            IFLA_LINKMODE: self.rta_uint8,
+            IFLA_LINKINFO: self.rta_linkinfo,
+            IFLA_NET_NS_PID: self.rta_uint32,
+            IFLA_IFALIAS: self.rta_string,
+            IFLA_NUM_VF: self.rta_uint32,
+            IFLA_VFINFO_LIST: self.rta_none,
+            IFLA_STATS64: self.rta_none,
+            IFLA_VF_PORTS: self.rta_none,
+            IFLA_PORT_SELF: self.rta_none,
+            IFLA_AF_SPEC: self.rta_af_spec,
+            IFLA_GROUP: self.rta_none,
+            IFLA_NET_NS_FD: self.rta_none,
+            IFLA_EXT_MASK: self.rta_none,
+        }
+        return fns;
+
+    def rta_fn(self, rta_type):
+        fns = {
+            IFLA_UNSPEC: self.rta_wtf,
+            IFLA_ADDRESS: self.rta_uint8_array,
+            IFLA_BROADCAST: self.rta_uint8_array,
+            IFLA_IFNAME: self.rta_string,
+            IFLA_MTU: self.rta_uint32,
+            IFLA_LINK: self.rta_uint32,
+            IFLA_QDISC: self.rta_string,
+            IFLA_STATS: self.rta_none,
+            IFLA_COST: self.rta_none,
+            IFLA_PRIORITY: self.rta_none,
+            IFLA_MASTER: self.rta_uint32,
+            IFLA_WIRELESS: self.rta_none,
+            IFLA_PROTINFO: self.rta_none,
+            IFLA_TXQLEN: self.rta_uint32,
+            IFLA_MAP: self.rta_none,
+            IFLA_WEIGHT: self.rta_uint32,
+            IFLA_OPERSTATE: self.rta_uint8,
+            IFLA_LINKMODE: self.rta_uint8,
+            IFLA_LINKINFO: self.rta_linkinfo,
+            IFLA_NET_NS_PID: self.rta_uint32,
+            IFLA_IFALIAS: self.rta_string,
+            IFLA_NUM_VF: self.rta_uint32,
+            IFLA_VFINFO_LIST: self.rta_none,
+            IFLA_STATS64: self.rta_none,
+            IFLA_VF_PORTS: self.rta_none,
+            IFLA_PORT_SELF: self.rta_none,
+            IFLA_AF_SPEC: self.rta_af_spec,
+            IFLA_GROUP: self.rta_none,
+            IFLA_NET_NS_FD: self.rta_none,
+            IFLA_EXT_MASK: self.rta_none,
+        }
+        return fns.get(rta_type)
+
+# passes address specific information
+
+# Important comment:
+# IFA_ADDRESS is prefix address, rather than local interface address.
+# It makes no difference for normally configured broadcast interfaces,
+# but for point-to-point IFA_ADDRESS is DESTINATION address,
+# local address is supplied in IFA_LOCAL attribute.
+
+IFA_UNSPEC = 0
+IFA_ADDRESS = 1
+IFA_LOCAL = 2
+IFA_LABEL = 3
+IFA_BROADCAST = 4
+IFA_ANYCAST = 5
+IFA_CACHEINFO = 6
+IFA_MULTICAST = 7
+IFA_MAX = 7
+
+class Ifaddrmsg(Nlmsg):
+
+    _fields_ = [
+        ('ifa_family', c_uint8),
+        ('ifa_prefixlen', c_uint8), # The prefix length
+        ('ifa_flags', c_uint8),     # Flags
+        ('ifa_scope', c_uint8),     # Address scope
+        ('ifa_index', c_uint32),    # Link index
+    ]
+
+    _family_str = {
+        AF_INET: "inet",
+        AF_INET6: "inet6",
+    }
+
+    def dump(self):
+        print 'ifa_family', self.ifa_family
+        print 'ifa_prefixlen', self.ifa_prefixlen
+        print 'ifa_flags 0x%02x' % self.ifa_flags
+        print 'ifa_scope', self.ifa_scope
+        print 'ifa_index', self.ifa_index
+
+    def rta_fn(self, rta_type):
+        fns = {
+            IFA_ADDRESS: self.rta_addr,
+            IFA_LOCAL: self.rta_addr,
+            IFA_LABEL: self.rta_string,
+            IFA_BROADCAST: self.rta_addr,
+            IFA_ANYCAST: self.rta_addr,
+            IFA_CACHEINFO: self.rta_none,
+            IFA_MULTICAST: self.rta_addr,
+        }
+        return fns.get(rta_type)
+
+class RtNetlinkError(Exception):
+
+    def __init__(self, message):
+        Exception.__init__(self, message)
+        logger.error(message)
+
+class RtNetlink(Netlink):
+
+    def __init__(self, pid):
+        Netlink.__init__(self, pid, NETLINK_ROUTE)
+
+    _rt_nlmsg_type_str = {
+        RTM_NEWROUTE: "RTM_NEWROUTE",
+        RTM_DELROUTE: "RTM_DELROUTE",
+        RTM_NEWLINK: "RTM_NEWLINK",
+        RTM_SETLINK: "RTM_SETLINK",
+        RTM_DELLINK: "RTM_DELLINK",
+        RTM_GETLINK: "RTM_GETLINK",
+        RTM_NEWADDR: "RTM_NEWADDR",
+        RTM_DELADDR: "RTM_DELADDR",
+    }
+
+    def _hexdump(self, buf):
+        while buf:
+            chunk = buf[:16]
+            buf = buf[16:]
+            nums = ["%02x" % c for c in chunk]
+            txt = [chr(c) if chr(c) in printable[:-5] else '.' for c in chunk]
+            print " ".join(nums).ljust(48), "".join(txt)
+
+    def dump(self, nlh):
+        nlmsg = self.nlmsg(nlh)
+        print
+        self._hexdump(self.sendbuf[:nlh.nlmsg_len])
+        print
+        nlh.dump()
+        print
+        nlmsg.dump()
+        print
+        nlmsg.dump_rtas()
+
+    def nlmsg(self, nlh):
+        nlmsg_struct = {
+            RTM_NEWROUTE: Rtmsg,
+            RTM_DELROUTE: Rtmsg,
+            RTM_GETROUTE: Rtmsg,
+            RTM_NEWLINK: Ifinfomsg,
+            RTM_SETLINK: Ifinfomsg,
+            RTM_DELLINK: Ifinfomsg,
+            RTM_GETLINK: Rtgenmsg,
+            RTM_NEWADDR: Ifaddrmsg,
+            RTM_DELADDR: Ifaddrmsg,
+            RTM_GETADDR: Rtgenmsg,
+        }
+        nldata = NLMSG_DATA(nlh)
+        nlmsg = nlmsg_struct[nlh.nlmsg_type].from_address(nldata)
+        nlmsg.nlh = nlh
+        return nlmsg
+
+    def _nl_cb(self, nlh):
+#        print "nl cb", self._rt_nlmsg_type_str[nlh.nlmsg_type]
+
+        if nlh.nlmsg_type in self._cbs:
+
+            nlmsg = self.nlmsg(nlh)
+
+            # validate nl length
+            if nlh.nlmsg_len - NLMSG_LENGTH(sizeof(nlmsg)) < 0:
+                raise RtNetlinkError("invalid nl length")
+
+            self._cbs[nlh.nlmsg_type](nlh, nlmsg)
+
+    def bind(self, groups, cbs):
+        self._cbs = cbs
+        Netlink.bind(self, groups, self._nl_cb)
+
+    def request(self, nlmsg_type, flags, extra, rtas={}):
+
+        nlh = Nlmsghdr.from_buffer(self.sendbuf)
+        nlh_p = addressof(nlh)
+
+        seq = self.seq
+        pid = self.pid
+
+        nlh.nlmsg_len = NLMSG_HDRLEN()
+        nlh.nlmsg_type = nlmsg_type
+        nlh.nlmsg_flags = flags
+        nlh.nlmsg_pid = pid
+        nlh.nlmsg_seq = seq
+
+        nlmsg = self.nlmsg(nlh)
+
+        nlh.nlmsg_len += nlmsg.pack_extra(extra, nlh_p + nlh.nlmsg_len)
+        nlh.nlmsg_len += nlmsg.pack_rtas_new(rtas, nlh_p + nlh.nlmsg_len,
+                                             nlmsg.rta_policy())
+        #self.dump(nlh)
+        self.sendall(string_at(nlh_p, nlh.nlmsg_len))
+        self.seq += 1
+
+        token = (pid, seq)
+        return token
diff --git a/ifupdown/rtnetlink_api.py b/ifupdown/rtnetlink_api.py
new file mode 100644 (file)
index 0000000..f9bba10
--- /dev/null
@@ -0,0 +1,237 @@
+#!/usr/bin/env python
+#
+# Copyright 2014 Cumulus Networks, Inc. All rights reserved.
+#
+# Author: Roopa Prabhu, roopa@cumulusnetworks.com
+#
+#
+
+from os import getpid
+from socket import AF_UNSPEC
+from socket import AF_BRIDGE
+from iff import IFF_UP
+from rtnetlink import *
+import os
+import ifupdownmain
+
+class rtnetlinkApi(RtNetlink):
+
+    bind_done = False
+
+    def __init__(self, pid):
+        RtNetlink.__init__(self, pid)
+        self.logger = logging.getLogger('ifupdown.' +
+                            self.__class__.__name__)
+        self.bind(0, None)
+        self.bind_done = True
+        self.ifindexmap = {}
+
+    def do_bind(self):
+        if self.bind_done:
+            return True
+        self.bind(0, None)
+        self.bind_done = True
+
+    def get_ifindex(self, ifname):
+        ifindex = self.ifindexmap.get(ifname)
+        if not ifindex:
+            with open('/sys/class/net/%s/ifindex' %ifname, 'r') as f:
+                ifindex = int(f.read())
+                self.ifindexmap[ifname] = ifindex
+        return ifindex
+
+    def create_vlan(self, link, ifname, vlanid):
+        self.logger.info('rtnetlink: creating vlan interface %s' %ifname)
+        if ifupdownmain.ifupdownFlags.DRYRUN:
+            return
+        try:
+            ifindex = self.get_ifindex(link)
+        except Exception, e:
+            raise Exception('cannot determine ifindex for link %s (%s)'
+                            %(link, str(e)))
+
+        ifm = Ifinfomsg(AF_UNSPEC)
+        rtas = {IFLA_IFNAME: ifname,
+                    IFLA_LINK : ifindex,
+                           IFLA_LINKINFO : {
+                                   IFLA_INFO_KIND : 'vlan',
+                                   IFLA_INFO_DATA : {
+                            IFLA_VLAN_ID : vlanid,
+                        }
+                    }
+               }
+        token = self.request(RTM_NEWLINK,
+                        NLM_F_CREATE | NLM_F_REQUEST | NLM_F_ACK, ifm, rtas)
+        self.process_wait([token])
+
+    def create_macvlan(self, ifname, link, mode='private'):
+        self.logger.info('rtnetlink: creating macvlan interface %s' %ifname)
+        if ifupdownmain.ifupdownFlags.DRYRUN:
+            return
+        try:
+            ifindex = self.get_ifindex(link)
+        except Exception, e:
+            raise Exception('cannot determine ifindex for link %s (%s)'
+                            %(link, str(e)))
+
+        ifm = Ifinfomsg(AF_UNSPEC)
+        rtas = {IFLA_IFNAME: ifname,
+                    IFLA_LINK : ifindex,
+                           IFLA_LINKINFO : {
+                                   IFLA_INFO_KIND : 'macvlan',
+                           IFLA_INFO_DATA : {
+                           IFLA_MACVLAN_MODE : MACVLAN_MODE_PRIVATE,
+                        }
+                    }
+               }
+        token = self.request(RTM_NEWLINK, NLM_F_CREATE | NLM_F_REQUEST |
+                             NLM_F_ACK, ifm, rtas)
+        self.process_wait([token])
+
+    def link_set(self, ifname, state):
+        flags = 0
+        self.logger.info('rtnetlink: setting link %s %s' %(ifname, state))
+        if ifupdownmain.ifupdownFlags.DRYRUN:
+            return
+
+        if state == "up":
+            flags |= IFF_UP
+        else:
+            flags &= ~IFF_UP
+
+        ifm = Ifinfomsg(AF_UNSPEC, ifi_change=IFF_UP, ifi_flags=flags)
+        rtas = {IFLA_IFNAME: ifname}
+
+        token = self.request(RTM_NEWLINK, NLM_F_REQUEST | NLM_F_ACK, ifm, rtas)
+        self.process_wait([token])
+
+    def link_set_hwaddress(self, ifname, hwaddress):
+        flags = 0
+        self.logger.info('rtnetlink: setting link hwaddress %s %s' %(ifname, hwaddress))
+        if ifupdownmain.ifupdownFlags.DRYRUN:
+            return
+
+        flags &= ~IFF_UP
+        ifm = Ifinfomsg(AF_UNSPEC, ifi_change=IFF_UP)
+        rtas = {IFLA_IFNAME: ifname,
+                IFLA_ADDRESS : str(bytearray([int(a,16) for a in hwaddress.split(':')]))}
+
+        self.logger.info(rtas)
+
+        token = self.request(RTM_NEWLINK, NLM_F_REQUEST | NLM_F_ACK, ifm, rtas)
+        self.process_wait([token])
+
+    def addr_add(self, ifname, address, broadcast=None, peer=None, scope=None,
+                 preferred_lifetime=None):
+        self.logger.info('rtnetlink: setting address')
+        if ifupdownmain.ifupdownFlags.DRYRUN:
+            return
+
+        try:
+            ifindex = self.get_ifindex(link)
+        except Exception, e:
+            raise Exception('cannot determine ifindex for link %s (%s)'
+                            %(link, str(e)))
+        ifa_scope = RT_SCOPE_
+        if scope:
+            if scope == "universe":
+                ifa_scope = RT_SCOPE_UNIVERSE
+            elif scope == "site":
+                ifa_scope = RT_SCOPE_SITE
+            elif scope == "link":
+                ifa_scope = RT_SCOPE_LINK
+            elif scope == "host":
+                ifa_scope = RT_SCOPE_HOST
+            elif scope == "nowhere":
+                ifa_scope = RT_SCOPE_NOWHERE
+        rtas = {IFLA_ADDRESS: ifname}
+
+        ifa = Ifaddrmsg(AF_UNSPEC, ifa_scope=ifa_scope, ifa_index=ifindex)
+
+        token = self.request(RTM_NEWADDR, NLM_F_REQUEST | NLM_F_ACK, ifa, rtas)
+        self.process_wait([token])
+
+    def link_set_many(self, ifname, ifattrs):
+        _ifattr_to_rta_map = {'dev' : IFLA_NAME,
+                              'address' : IFLA_ADDRESS,
+                              'broadcast' : IFLA_BROADCAST,
+                              'mtu' : IFLA_MTU,
+                              'master' : IFLA_MASTER}
+        flags = 0
+        ifi_change = IFF_UP
+        rtas = {}
+        self.logger.info('rtnetlink: setting link %s %s' %(ifname, state))
+        if ifupdownmain.ifupdownFlags.DRYRUN:
+            return
+        if not ifattrs:
+           return
+        state = ifattrs.get('state')
+        if state == 'up':
+            flags |= IFF_UP
+        elif state == 'down':
+            flags &= ~IFF_UP
+        else:
+            ifi_change = 0
+
+        if ifi_change:
+           ifm = Ifinfomsg(AF_UNSPEC, ifi_change=IFF_UP, ifi_flags=flags)
+        else:
+           ifm = Ifinfomsg(AF_UNSPEC)
+
+        for attr, attrval in ifattrs.items():
+            rta_attr = _ifattr_to_rta_map.get(attr)
+            if rta_attr:
+               if attr == 'hwaddress':
+                  rtas[rta_attr] = str(bytearray([int(a,16) for a in attrval.split(':')]))
+               else:
+                  rtas[rta_attr] = attrval
+
+        token = self.request(RTM_NEWLINK, NLM_F_REQUEST | NLM_F_ACK, ifm, rtas)
+        self.process_wait([token])
+
+    def bridge_vlan(self, add=True, vid=None, dev=None, pvid=False,
+                    untagged=False, master=True):
+        flags = 0
+        vflags = 0
+        if not vid or not dev:
+           return
+        self.logger.info('rtnetlink: bridge vlan add vid %s %s %s dev %s %s'
+                         %(vid, 'untagged' if untagged else '',
+                           'pvid' if pvid else '', dev,
+                           'self' if self else ''))
+        if ifupdownmain.ifupdownFlags.DRYRUN:
+            return
+        try:
+            ifindex = self.get_ifindex(dev)
+        except Exception, e:
+            raise Exception('cannot determine ifindex for dev %s (%s)'
+                            %(dev, str(e)))
+        if not master:
+            flags = BRIDGE_FLAGS_SELF
+
+        if pvid:
+           vflags = BRIDGE_VLAN_INFO_PVID
+           vflags |= BRIDGE_VLAN_INFO_UNTAGGED
+        elif untagged:
+           vflags |= BRIDGE_VLAN_INFO_UNTAGGED
+
+        ifm = Ifinfomsg(AF_BRIDGE, ifi_index=ifindex)
+        rtas = {IFLA_AF_SPEC: {
+                    IFLA_BRIDGE_FLAGS: flags,
+                    IFLA_BRIDGE_VLAN_INFO : BridgeVlanInfo(vflags, int(vid), int(vid))
+                  }
+               }
+        if add:
+            token = self.request(RTM_SETLINK,
+                        NLM_F_REQUEST | NLM_F_ACK, ifm, rtas)
+        else:
+            token = self.request(RTM_DELLINK,
+                        NLM_F_REQUEST | NLM_F_ACK, ifm, rtas)
+        self.process_wait([token])
+
+    def bridge_vlan_many(self, add=True, vids=[], dev=None, pvid=False,
+                         untagged=False, master=True):
+        for v in vids:
+            self.bridge_vlan_add(add, v, dev, ispvid, isuntagged, master)
+
+rtnl_api = rtnetlinkApi(os.getpid())
diff --git a/ifupdown/scheduler.py b/ifupdown/scheduler.py
new file mode 100644 (file)
index 0000000..af9f28c
--- /dev/null
@@ -0,0 +1,531 @@
+#!/usr/bin/python
+#
+# Copyright 2014 Cumulus Networks, Inc. All rights reserved.
+# Author: Roopa Prabhu, roopa@cumulusnetworks.com
+#
+# ifaceScheduler --
+#    interface scheduler
+#
+
+from statemanager import *
+from iface import *
+from graph import *
+from collections import deque
+from collections import OrderedDict
+import logging
+import traceback
+import sys
+from graph import *
+from collections import deque
+from threading import *
+from ifupdownbase import *
+from sets import Set
+
+class ifaceSchedulerFlags():
+    """ Enumerates scheduler flags """
+
+    INORDER = 0x1
+    POSTORDER = 0x2
+
+class ifaceScheduler():
+    """ scheduler functions to schedule configuration of interfaces.
+
+    supports scheduling of interfaces serially in plain interface list
+    or dependency graph format.
+
+    """
+
+    _STATE_CHECK = True
+
+    _SCHED_RETVAL = True
+
+    @classmethod
+    def run_iface_op(cls, ifupdownobj, ifaceobj, op, cenv=None):
+        """ Runs sub operation on an interface """
+        ifacename = ifaceobj.name
+
+        if ifupdownobj.type and ifupdownobj.type != ifaceobj.type:
+            return
+
+        if not ifupdownobj.ADDONS_ENABLE: return
+        if op == 'query-checkcurr':
+            query_ifaceobj=ifupdownobj.create_n_save_ifaceobjcurr(ifaceobj)
+            # If not type bridge vlan and the object does not exist,
+            # mark not found and return
+            if (not ifupdownobj.link_exists(ifaceobj.name) and
+                ifaceobj.type != ifaceType.BRIDGE_VLAN):
+                query_ifaceobj.set_state_n_status(ifaceState.from_str(op),
+                                                  ifaceStatus.NOTFOUND)
+                return
+        for mname in ifupdownobj.module_ops.get(op):
+            m = ifupdownobj.modules.get(mname)
+            err = 0
+            try:
+                if hasattr(m, 'run'):
+                    msg = ('%s: %s : running module %s' %(ifacename, op, mname))
+                    if op == 'query-checkcurr':
+                        # Dont check curr if the interface object was 
+                        # auto generated
+                        if (ifaceobj.priv_flags & ifupdownobj.NOCONFIG):
+                            continue
+                        ifupdownobj.logger.debug(msg)
+                        m.run(ifaceobj, op, query_ifaceobj,
+                              ifaceobj_getfunc=ifupdownobj.get_ifaceobjs)
+                    else:
+                        ifupdownobj.logger.debug(msg)
+                        m.run(ifaceobj, op,
+                              ifaceobj_getfunc=ifupdownobj.get_ifaceobjs)
+            except Exception, e:
+                if not ifupdownobj.ignore_error(str(e)):
+                   err = 1
+                   ifupdownobj.logger.warn(str(e))
+                # Continue with rest of the modules
+                pass
+            finally:
+                if err or ifaceobj.status == ifaceStatus.ERROR:
+                    ifaceobj.set_state_n_status(ifaceState.from_str(op),
+                                                ifaceStatus.ERROR)
+                    if 'up' in  op or 'down' in op:
+                        cls._SCHED_RETVAL = False
+                else:
+                    # Mark success only if the interface was not already
+                    # marked with error
+                    status = (ifaceobj.status
+                              if ifaceobj.status == ifaceStatus.ERROR
+                              else ifaceStatus.SUCCESS)
+                    ifaceobj.set_state_n_status(ifaceState.from_str(op),
+                                                status)
+
+        if ifupdownobj.config.get('addon_scripts_support', '0') == '1':
+            # execute /etc/network/ scripts 
+            for mname in ifupdownobj.script_ops.get(op, []):
+                ifupdownobj.logger.debug('%s: %s : running script %s'
+                    %(ifacename, op, mname))
+                try:
+                    ifupdownobj.exec_command(mname, cmdenv=cenv)
+                except Exception, e:
+                    ifupdownobj.log_error(str(e))
+
+    @classmethod
+    def run_iface_list_ops(cls, ifupdownobj, ifaceobjs, ops):
+        """ Runs all operations on a list of interface
+            configurations for the same interface
+        """
+
+        # minor optimization. If operation is 'down', proceed only
+        # if interface exists in the system
+        ifacename = ifaceobjs[0].name
+        ifupdownobj.logger.info('%s: running ops ...' %ifacename)
+        if ('down' in ops[0] and
+                ifaceobjs[0].type != ifaceType.BRIDGE_VLAN and
+                not ifupdownobj.link_exists(ifacename)):
+            ifupdownobj.logger.debug('%s: does not exist' %ifacename)
+            # run posthook before you get out of here, so that
+            # appropriate cleanup is done
+            posthookfunc = ifupdownobj.sched_hooks.get('posthook')
+            if posthookfunc:
+                for ifaceobj in ifaceobjs:
+                    ifaceobj.status = ifaceStatus.SUCCESS
+                    posthookfunc(ifupdownobj, ifaceobj, 'down')
+            return 
+        for op in ops:
+            # first run ifupdownobj handlers. This is good enough
+            # for the first object in the list
+            handler = ifupdownobj.ops_handlers.get(op)
+            if handler:
+                try:
+                    handler(ifupdownobj, ifaceobjs[0])
+                except Exception, e:
+                    if not ifupdownobj.link_master_slave_ignore_error(str(e)):
+                       ifupdownobj.logger.warn('%s: %s'
+                                   %(ifaceobjs[0].name, str(e)))
+                    pass
+            for ifaceobj in ifaceobjs:
+                cls.run_iface_op(ifupdownobj, ifaceobj, op,
+                    cenv=ifupdownobj.generate_running_env(ifaceobj, op)
+                        if ifupdownobj.config.get('addon_scripts_support',
+                            '0') == '1' else None)
+        posthookfunc = ifupdownobj.sched_hooks.get('posthook')
+        if posthookfunc:
+            try:
+                [posthookfunc(ifupdownobj, ifaceobj, ops[0])
+                    for ifaceobj in ifaceobjs]
+            except Exception, e:
+                ifupdownobj.logger.warn('%s' %str(e))
+                pass
+
+    @classmethod
+    def _check_upperifaces(cls, ifupdownobj, ifaceobj, ops, parent,
+                           followdependents=False):
+        """ Check if upperifaces are hanging off us and help caller decide
+        if he can proceed with the ops on this device
+
+        Returns True or False indicating the caller to proceed with the
+        operation.
+        """
+        # proceed only for down operation
+        if 'down' not in ops[0]:
+            return True
+
+        if (ifupdownobj.FORCE or
+                not ifupdownobj.ADDONS_ENABLE or
+                (not ifupdownobj.is_ifaceobj_noconfig(ifaceobj) and
+                ifupdownobj.config.get('warn_on_ifdown', '0') == '0' and
+                not ifupdownobj.ALL)):
+            return True
+
+        ulist = ifaceobj.upperifaces
+        if not ulist:
+            return True
+
+        # Get the list of upper ifaces other than the parent
+        tmpulist = ([u for u in ulist if u != parent] if parent
+                    else ulist)
+        if not tmpulist:
+            return True
+        # XXX: This is expensive. Find a cheaper way to do this.
+        # if any of the upperdevs are present,
+        # return false to the caller to skip this interface
+        for u in tmpulist:
+            if ifupdownobj.link_exists(u):
+                if not ifupdownobj.ALL:
+                    if ifupdownobj.is_ifaceobj_noconfig(ifaceobj):
+                        ifupdownobj.logger.info('%s: skipping interface down,'
+                            %ifaceobj.name + ' upperiface %s still around ' %u)
+                    else:
+                        ifupdownobj.logger.warn('%s: skipping interface down,'
+                            %ifaceobj.name + ' upperiface %s still around ' %u)
+                return False
+        return True
+
+    @classmethod
+    def run_iface_graph(cls, ifupdownobj, ifacename, ops, parent=None,
+                        order=ifaceSchedulerFlags.POSTORDER,
+                        followdependents=True):
+        """ runs interface by traversing all nodes rooted at itself """
+
+        # Each ifacename can have a list of iface objects
+        ifaceobjs = ifupdownobj.get_ifaceobjs(ifacename)
+        if not ifaceobjs:
+            raise Exception('%s: not found' %ifacename)
+
+        # Check state of the dependent. If it is already brought up, return
+        if (cls._STATE_CHECK and
+            (ifaceobjs[0].state == ifaceState.from_str(ops[-1]))):
+            ifupdownobj.logger.debug('%s: already processed' %ifacename)
+            return
+
+        for ifaceobj in ifaceobjs:
+            if not cls._check_upperifaces(ifupdownobj, ifaceobj,
+                                          ops, parent, followdependents):
+               return
+
+        # If inorder, run the iface first and then its dependents
+        if order == ifaceSchedulerFlags.INORDER:
+            cls.run_iface_list_ops(ifupdownobj, ifaceobjs, ops)
+
+        for ifaceobj in ifaceobjs:
+            # Run lowerifaces or dependents
+            dlist = ifaceobj.lowerifaces
+            if dlist:
+                ifupdownobj.logger.debug('%s: found dependents %s'
+                            %(ifacename, str(dlist)))
+                try:
+                    if not followdependents:
+                        # XXX: this is yet another extra step,
+                        # but is needed for interfaces that are
+                        # implicit dependents. even though we are asked to
+                        # not follow dependents, we must follow the ones
+                        # that dont have user given config. Because we own them
+                        new_dlist = [d for d in dlist
+                                    if ifupdownobj.is_iface_noconfig(d)]
+                        if new_dlist:
+                            cls.run_iface_list(ifupdownobj, new_dlist, ops,
+                                           ifacename, order, followdependents,
+                                           continueonfailure=False)
+                    else:
+                        cls.run_iface_list(ifupdownobj, dlist, ops,
+                                            ifacename, order,
+                                            followdependents,
+                                            continueonfailure=False)
+                except Exception, e:
+                    if (ifupdownobj.ignore_error(str(e))):
+                        pass
+                    else:
+                        # Dont bring the iface up if children did not come up
+                        ifaceobj.set_state_n_status(ifaceState.NEW,
+                                                ifaceStatus.ERROR)
+                        raise
+        if order == ifaceSchedulerFlags.POSTORDER:
+            cls.run_iface_list_ops(ifupdownobj, ifaceobjs, ops)
+
+    @classmethod
+    def run_iface_list(cls, ifupdownobj, ifacenames,
+                       ops, parent=None, order=ifaceSchedulerFlags.POSTORDER,
+                       followdependents=True, continueonfailure=True):
+        """ Runs interface list """
+
+        for ifacename in ifacenames:
+            try:
+              cls.run_iface_graph(ifupdownobj, ifacename, ops, parent,
+                      order, followdependents)
+            except Exception, e:
+                if continueonfailure:
+                    if ifupdownobj.logger.isEnabledFor(logging.DEBUG):
+                        traceback.print_tb(sys.exc_info()[2])
+                    ifupdownobj.logger.error('%s : %s' %(ifacename, str(e)))
+                    pass
+                else:
+                    if (ifupdownobj.ignore_error(str(e))):
+                        pass
+                    else:
+                        raise Exception('%s : (%s)' %(ifacename, str(e)))
+
+    @classmethod
+    def run_iface_graph_upper(cls, ifupdownobj, ifacename, ops, parent=None,
+                        followdependents=True, skip_root=False):
+        """ runs interface by traversing all nodes rooted at itself """
+
+        # Each ifacename can have a list of iface objects
+        ifaceobjs = ifupdownobj.get_ifaceobjs(ifacename)
+        if not ifaceobjs:
+            raise Exception('%s: not found' %ifacename)
+
+        if (cls._STATE_CHECK and
+            (ifaceobjs[0].state == ifaceState.from_str(ops[-1]))):
+            ifupdownobj.logger.debug('%s: already processed' %ifacename)
+            return
+
+        if not skip_root:
+            # run the iface first and then its upperifaces
+            cls.run_iface_list_ops(ifupdownobj, ifaceobjs, ops)
+        for ifaceobj in ifaceobjs:
+            # Run upperifaces
+            ulist = ifaceobj.upperifaces
+            if ulist:
+                ifupdownobj.logger.debug('%s: found upperifaces %s'
+                                            %(ifacename, str(ulist)))
+                try:
+                    cls.run_iface_list_upper(ifupdownobj, ulist, ops,
+                                            ifacename,
+                                            followdependents,
+                                            continueonfailure=True)
+                except Exception, e:
+                    if (ifupdownobj.ignore_error(str(e))):
+                        pass
+                    else:
+                        raise
+
+    @classmethod
+    def run_iface_list_upper(cls, ifupdownobj, ifacenames,
+                       ops, parent=None, followdependents=True,
+                       continueonfailure=True, skip_root=False):
+        """ Runs interface list """
+
+        for ifacename in ifacenames:
+            try:
+              cls.run_iface_graph_upper(ifupdownobj, ifacename, ops, parent,
+                      followdependents, skip_root)
+            except Exception, e:
+                if ifupdownobj.logger.isEnabledFor(logging.DEBUG):
+                    traceback.print_tb(sys.exc_info()[2])
+                ifupdownobj.logger.warn('%s : %s' %(ifacename, str(e)))
+                pass
+
+    @classmethod
+    def _get_valid_upperifaces(cls, ifupdownobj, ifacenames,
+                               allupperifacenames):
+        """ Recursively find valid upperifaces
+
+        valid upperifaces are:
+            - An upperiface which had no user config (example builtin
+              interfaces. usually vlan interfaces.)
+            - or had config and previously up
+            - and interface currently does not exist
+            - or is a bridge (because if your upperiface was a bridge
+            - u will have to execute up on the bridge
+              to enslave the port and apply bridge attributes to the port) """
+
+        upperifacenames = []
+        for ifacename in ifacenames:
+            # get upperifaces
+            ifaceobj = ifupdownobj.get_ifaceobj_first(ifacename)
+            if not ifaceobj:
+               continue
+            ulist = Set(ifaceobj.upperifaces).difference(upperifacenames)
+            nulist = []
+            for u in ulist:
+                uifaceobj = ifupdownobj.get_ifaceobj_first(u)
+                if not uifaceobj:
+                   continue
+                has_config = not bool(uifaceobj.priv_flags
+                                   & ifupdownobj.NOCONFIG)
+                if (((has_config and ifupdownobj.get_ifaceobjs_saved(u)) or
+                     not has_config) and (not ifupdownobj.link_exists(u)
+                         or uifaceobj.link_kind == ifaceLinkKind.BRIDGE)):
+                     nulist.append(u)
+            upperifacenames.extend(nulist)
+        allupperifacenames.extend(upperifacenames)
+        if upperifacenames:
+            cls._get_valid_upperifaces(ifupdownobj, upperifacenames,
+                                       allupperifacenames)
+        return
+
+    @classmethod
+    def run_upperifaces(cls, ifupdownobj, ifacenames, ops,
+                        continueonfailure=True):
+        """ Run through valid upperifaces """ 
+        upperifaces = []
+
+        cls._get_valid_upperifaces(ifupdownobj, ifacenames, upperifaces)
+        if not upperifaces:
+           return
+        # dump valid upperifaces
+        ifupdownobj.logger.debug(upperifaces)
+        for u in upperifaces:
+            try:
+                ifaceobjs = ifupdownobj.get_ifaceobjs(u)
+                if not ifaceobjs:
+                   continue
+                cls.run_iface_list_ops(ifupdownobj, ifaceobjs, ops)
+            except Exception, e:
+                if continueonfailure:
+                   self.logger.warn('%s' %str(e))
+
+    @classmethod
+    def get_sorted_iface_list(cls, ifupdownobj, ifacenames, ops,
+                              dependency_graph, indegrees=None):
+        if len(ifacenames) == 1:
+            return ifacenames
+        # Get a sorted list of all interfaces
+        if not indegrees:
+            indegrees = OrderedDict()
+            for ifacename in dependency_graph.keys():
+                indegrees[ifacename] = ifupdownobj.get_iface_refcnt(ifacename)
+        ifacenames_all_sorted = graph.topological_sort_graphs_all(
+                                        dependency_graph, indegrees)
+        # if ALL was set, return all interfaces
+        if ifupdownobj.ALL:
+            return ifacenames_all_sorted
+
+        # else return ifacenames passed as argument in sorted order
+        ifacenames_sorted = []
+        [ifacenames_sorted.append(ifacename)
+                        for ifacename in ifacenames_all_sorted
+                            if ifacename in ifacenames]
+        return ifacenames_sorted
+
+    @classmethod
+    def sched_ifaces(cls, ifupdownobj, ifacenames, ops,
+                dependency_graph=None, indegrees=None,
+                order=ifaceSchedulerFlags.POSTORDER,
+                followdependents=True, skipupperifaces=False, sort=False):
+        """ runs interface configuration modules on interfaces passed as
+            argument. Runs topological sort on interface dependency graph.
+
+        Args:
+            **ifupdownobj** (object): ifupdownMain object 
+
+            **ifacenames** (list): list of interface names
+
+            **ops** : list of operations to perform eg ['pre-up', 'up', 'post-up']
+
+            **dependency_graph** (dict): dependency graph in adjacency list format
+
+        Kwargs:
+            **indegrees** (dict): indegree array of the dependency graph
+
+            **order** (int): ifaceSchedulerFlags (POSTORDER, INORDER)
+
+            **followdependents** (bool): follow dependent interfaces if true
+
+            **sort** (bool): sort ifacelist in the case where ALL is not set
+
+        """
+        #
+        # Algo:
+        # if ALL/auto interfaces are specified,
+        #   - walk the dependency tree in postorder or inorder depending
+        #     on the operation.
+        #     (This is to run interfaces correctly in order)
+        # else:
+        #   - sort iface list if the ifaces belong to a "class"
+        #   - else just run iface list in the order they were specified
+        #
+        # Run any upperifaces if available
+        #
+        followupperifaces = False
+        run_queue = []
+        skip_ifacesort = int(ifupdownobj.config.get('skip_ifacesort', '0'))
+        if not skip_ifacesort and not indegrees:
+            indegrees = OrderedDict()
+            for ifacename in dependency_graph.keys():
+                indegrees[ifacename] = ifupdownobj.get_iface_refcnt(ifacename)
+
+        if not ifupdownobj.ALL:
+            if 'up' in ops[0]:
+                # If there is any interface that does not exist, maybe it
+                # is a logical interface and we have to followupperifaces
+                # when it comes up, so lets get that list.
+                if any([True for i in ifacenames
+                        if ifupdownobj.must_follow_upperifaces(i)]):
+                    followupperifaces = (True if
+                                    [i for i in ifacenames
+                                        if not ifupdownobj.link_exists(i)]
+                                        else False)
+            # sort interfaces only if the caller asked to sort
+            # and skip_ifacesort is not on.
+            if not skip_ifacesort and sort:
+                run_queue = cls.get_sorted_iface_list(ifupdownobj, ifacenames,
+                                    ops, dependency_graph, indegrees)
+                if run_queue and 'up' in ops[0]:
+                    run_queue.reverse()
+        else:
+            # if -a is set, we pick the interfaces
+            # that have no parents and use a sorted list of those
+            if not skip_ifacesort:
+                sorted_ifacenames = cls.get_sorted_iface_list(ifupdownobj,
+                                            ifacenames, ops, dependency_graph,
+                                            indegrees)
+                if sorted_ifacenames:
+                    # pick interfaces that user asked
+                    # and those that dont have any dependents first
+                    [run_queue.append(ifacename)
+                        for ifacename in sorted_ifacenames
+                            if ifacename in ifacenames and
+                            not indegrees.get(ifacename)]
+                    ifupdownobj.logger.debug('graph roots (interfaces that ' +
+                            'dont have dependents):' + ' %s' %str(run_queue))
+                else:
+                    ifupdownobj.logger.warn('interface sort returned None')
+
+        # If queue not present, just run interfaces that were asked by the
+        # user
+        if not run_queue:
+            run_queue = list(ifacenames)
+            # if we are taking the order of interfaces as specified
+            # in the interfaces file, we should reverse the list if we
+            # want to down. This can happen if 'skip_ifacesort'
+            # is been specified.
+            if 'down' in ops[0]:
+                run_queue.reverse()
+
+        # run interface list
+        cls.run_iface_list(ifupdownobj, run_queue, ops,
+                           parent=None, order=order,
+                           followdependents=followdependents)
+        if not cls._SCHED_RETVAL:
+            raise Exception()
+
+        if (not skipupperifaces and
+                ifupdownobj.config.get('skip_upperifaces', '0') == '0' and
+                ((not ifupdownobj.ALL and followdependents) or
+                followupperifaces) and
+                'up' in ops[0]):
+            # If user had given a set of interfaces to bring up
+            # try and execute 'up' on the upperifaces
+            ifupdownobj.logger.info('running upperifaces (parent interfaces) ' +
+                                    'if available ..')
+            cls._STATE_CHECK = False
+            cls.run_upperifaces(ifupdownobj, ifacenames, ops)
+            cls._STATE_CHECK = True
diff --git a/ifupdown/scheduler.py.orig b/ifupdown/scheduler.py.orig
new file mode 100644 (file)
index 0000000..99cc9a8
--- /dev/null
@@ -0,0 +1,429 @@
+#!/usr/bin/python
+#
+# Copyright 2013.  Cumulus Networks, Inc.
+# Author: Roopa Prabhu, roopa@cumulusnetworks.com
+#
+# ifaceScheduler --
+#    interface scheduler
+#
+
+from statemanager import *
+from iface import *
+from graph import *
+from collections import deque
+from collections import OrderedDict
+import logging
+import traceback
+import sys
+from graph import *
+from collections import deque
+from threading import *
+from ifupdownbase import *
+
+class ifaceSchedulerFlags():
+    INORDER = 0x1
+    POSTORDER = 0x2
+
+class ifaceScheduler():
+    """ scheduler functions to schedule configuration of interfaces.
+
+    supports scheduling of interfaces serially in plain interface list
+    or dependency graph format.
+
+    Algo:
+        - run topological sort on the iface objects
+        - In the sorted iface object list, pick up interfaces with no parents
+        and run ops on them and their children. 
+        - If operation is up and user gave interface list (ie not all)
+        option, also see if there were upper-devices and run ops on them. 
+        - if operation is down, dont down the interface if it still
+        has upperifaces present. The down operation is executed when the
+        last upperiface goes away. If force option is set, this rule does not
+        apply.
+        - run ops calls addon modules run operation passing the iface
+        object and op to each module.
+        - ops are [pre-up, up, post-up, pre-down, down,
+                   post-down, query-running, query-check]
+    """
+
+    _STATE_CHECK = True
+
+    _SCHED_RETVAL = True
+
+    @classmethod
+    def run_iface_op(cls, ifupdownobj, ifaceobj, op, cenv=None):
+        """ Runs sub operation on an interface """
+        ifacename = ifaceobj.name
+
+        if (cls._STATE_CHECK and
+            (ifaceobj.state >= ifaceState.from_str(op))):
+            ifupdownobj.logger.debug('%s: already in state %s' %(ifacename, op))
+            return
+        if not ifupdownobj.ADDONS_ENABLE: return
+        if op == 'query-checkcurr':
+            query_ifaceobj=ifupdownobj.create_n_save_ifaceobjcurr(ifaceobj)
+        for mname in ifupdownobj.module_ops.get(op):
+            m = ifupdownobj.modules.get(mname)
+            err = 0
+            try:
+                if hasattr(m, 'run'):
+                    msg = ('%s: %s : running module %s' %(ifacename, op, mname))
+                    if op == 'query-checkcurr':
+                        # Dont check curr if the interface object was 
+                        # auto generated
+                        if (ifaceobj.priv_flags & ifupdownobj.NOCONFIG):
+                            continue
+                        ifupdownobj.logger.debug(msg)
+                        m.run(ifaceobj, op, query_ifaceobj)
+                    else:
+                        ifupdownobj.logger.debug(msg)
+                        m.run(ifaceobj, op)
+            except Exception, e:
+                err = 1
+                ifupdownobj.log_error(str(e))
+                err = 0  # error can be ignored by log_error, in which case
+                         # reset err flag
+            finally:
+                if err or ifaceobj.status == ifaceStatus.ERROR:
+                    ifaceobj.set_state_n_status(ifaceState.from_str(op),
+                                                ifaceStatus.ERROR)
+                    if 'up' in  op or 'down' in op:
+                        cls._SCHED_RETVAL = False
+                else:
+                    ifaceobj.set_state_n_status(ifaceState.from_str(op),
+                                                ifaceStatus.SUCCESS)
+
+        if ifupdownobj.COMPAT_EXEC_SCRIPTS:
+            # execute /etc/network/ scripts 
+            for mname in ifupdownobj.script_ops.get(op, []):
+                ifupdownobj.logger.debug('%s: %s : running script %s'
+                    %(ifacename, op, mname))
+                try:
+                    ifupdownobj.exec_command(mname, cmdenv=cenv)
+                except Exception, e:
+                    ifupdownobj.log_error(str(e))
+
+    @classmethod
+    def run_iface_list_ops(cls, ifupdownobj, ifaceobjs, ops):
+        """ Runs all operations on a list of interface
+            configurations for the same interface
+        """
+        # minor optimization. If operation is 'down', proceed only
+        # if interface exists in the system
+        ifacename = ifaceobjs[0].name
+        if ('down' in ops[0] and
+                not ifupdownobj.link_exists(ifacename)):
+            ifupdownobj.logger.debug('%s: does not exist' %ifacename)
+            # run posthook before you get out of here, so that
+            # appropriate cleanup is done
+            posthookfunc = ifupdownobj.sched_hooks.get('posthook')
+            if posthookfunc:
+                for ifaceobj in ifaceobjs:
+                    ifaceobj.status = ifaceStatus.SUCCESS
+                    posthookfunc(ifupdownobj, ifaceobj, 'down')
+            return 
+        for op in ops:
+            # first run ifupdownobj handlers. This is good enough
+            # for the first object in the list
+            handler = ifupdownobj.ops_handlers.get(op)
+            if handler:
+                if (not ifaceobjs[0].addr_method or
+                    (ifaceobjs[0].addr_method and
+                    ifaceobjs[0].addr_method != 'manual')):
+                    handler(ifupdownobj, ifaceobjs[0])
+            for ifaceobj in ifaceobjs:
+                cls.run_iface_op(ifupdownobj, ifaceobj, op,
+                    cenv=ifupdownobj.generate_running_env(ifaceobj, op)
+                        if ifupdownobj.COMPAT_EXEC_SCRIPTS else None) 
+                posthookfunc = ifupdownobj.sched_hooks.get('posthook')
+                if posthookfunc:
+                    posthookfunc(ifupdownobj, ifaceobj, op)
+
+    @classmethod
+    def _check_upperifaces(cls, ifupdownobj, ifaceobj, ops, parent,
+                           followdependents=False):
+        """ Check if upperifaces are hanging off us and help caller decide
+        if he can proceed with the ops on this device
+
+        Returns True or False indicating the caller to proceed with the
+        operation.
+        """
+        # proceed only for down operation
+        if 'down' not in ops[0]:
+            return True
+
+        if (ifupdownobj.FORCE or
+                not ifupdownobj.ADDONS_ENABLE or
+                (not ifupdownobj.is_ifaceobj_noconfig(ifaceobj) and
+                ifupdownobj.config.get('warn_on_ifdown', '0') == '0' and
+                not ifupdownobj.ALL)):
+            return True
+
+        ulist = ifaceobj.upperifaces
+        if not ulist:
+            return True
+
+        # Get the list of upper ifaces other than the parent
+        tmpulist = ([u for u in ulist if u != parent] if parent
+                    else ulist)
+        if not tmpulist:
+            return True
+        # XXX: This is expensive. Find a cheaper way to do this.
+        # if any of the upperdevs are present,
+        # return false to the caller to skip this interface
+        for u in tmpulist:
+            if ifupdownobj.link_exists(u):
+                if not ifupdownobj.ALL:
+                    if ifupdownobj.is_ifaceobj_noconfig(ifaceobj):
+                        ifupdownobj.logger.info('%s: skipping interface down,'
+                            %ifaceobj.name + ' upperiface %s still around ' %u)
+                    else:
+                        ifupdownobj.logger.warn('%s: skipping interface down,'
+                            %ifaceobj.name + ' upperiface %s still around ' %u)
+                return False
+        return True
+
+    @classmethod
+    def run_iface_graph(cls, ifupdownobj, ifacename, ops, parent=None,
+                        order=ifaceSchedulerFlags.POSTORDER,
+                        followdependents=True):
+        """ runs interface by traversing all nodes rooted at itself """
+
+        # Each ifacename can have a list of iface objects
+        ifaceobjs = ifupdownobj.get_ifaceobjs(ifacename)
+        if not ifaceobjs:
+            raise Exception('%s: not found' %ifacename)
+
+        for ifaceobj in ifaceobjs:
+            if not cls._check_upperifaces(ifupdownobj, ifaceobj,
+                                          ops, parent, followdependents):
+                return
+
+        # If inorder, run the iface first and then its dependents
+        if order == ifaceSchedulerFlags.INORDER:
+            cls.run_iface_list_ops(ifupdownobj, ifaceobjs, ops)
+
+        for ifaceobj in ifaceobjs:
+            # Run lowerifaces or dependents
+            dlist = ifaceobj.lowerifaces
+            if dlist:
+                ifupdownobj.logger.debug('%s: found dependents %s'
+                            %(ifacename, str(dlist)))
+                try:
+                    if not followdependents:
+                        # XXX: this is yet another extra step,
+                        # but is needed for interfaces that are
+                        # implicit dependents. even though we are asked to
+                        # not follow dependents, we must follow the ones
+                        # that dont have user given config. Because we own them
+                        new_dlist = [d for d in dlist
+                                    if ifupdownobj.is_iface_noconfig(d)]
+                        if new_dlist:
+                            cls.run_iface_list(ifupdownobj, new_dlist, ops,
+                                           ifacename, order, followdependents,
+                                           continueonfailure=False)
+                    else:
+                        cls.run_iface_list(ifupdownobj, dlist, ops,
+                                            ifacename, order,
+                                            followdependents,
+                                            continueonfailure=False)
+                except Exception, e:
+                    if (ifupdownobj.ignore_error(str(e))):
+                        pass
+                    else:
+                        # Dont bring the iface up if children did not come up
+                        ifaceobj.set_state_n_status(ifaceState.NEW,
+                                                ifaceStatus.ERROR)
+                        raise
+        if order == ifaceSchedulerFlags.POSTORDER:
+            cls.run_iface_list_ops(ifupdownobj, ifaceobjs, ops)
+
+    @classmethod
+    def run_iface_list(cls, ifupdownobj, ifacenames,
+                       ops, parent=None, order=ifaceSchedulerFlags.POSTORDER,
+                       followdependents=True, continueonfailure=True):
+        """ Runs interface list """
+
+        for ifacename in ifacenames:
+            try:
+              cls.run_iface_graph(ifupdownobj, ifacename, ops, parent,
+                      order, followdependents)
+            except Exception, e:
+                if continueonfailure:
+                    if ifupdownobj.logger.isEnabledFor(logging.DEBUG):
+                        traceback.print_tb(sys.exc_info()[2])
+                    ifupdownobj.logger.error('%s : %s' %(ifacename, str(e)))
+                    pass
+                else:
+                    if (ifupdownobj.ignore_error(str(e))):
+                        pass
+                    else:
+                        raise Exception('%s : (%s)' %(ifacename, str(e)))
+
+    @classmethod
+    def run_iface_graph_upper(cls, ifupdownobj, ifacename, ops, parent=None,
+                        followdependents=True, skip_root=False):
+        """ runs interface by traversing all nodes rooted at itself """
+
+        # Each ifacename can have a list of iface objects
+        ifaceobjs = ifupdownobj.get_ifaceobjs(ifacename)
+        if not ifaceobjs:
+            raise Exception('%s: not found' %ifacename)
+
+        if not skip_root:
+            # run the iface first and then its upperifaces
+            cls.run_iface_list_ops(ifupdownobj, ifaceobjs, ops)
+        for ifaceobj in ifaceobjs:
+            # Run upperifaces
+            ulist = ifaceobj.upperifaces
+            if ulist:
+                ifupdownobj.logger.debug('%s: found upperifaces %s'
+                                            %(ifacename, str(ulist)))
+                try:
+                    cls.run_iface_list_upper(ifupdownobj, ulist, ops,
+                                            ifacename,
+                                            followdependents,
+                                            continueonfailure=True)
+                except Exception, e:
+                    if (ifupdownobj.ignore_error(str(e))):
+                        pass
+                    else:
+                        raise
+
+    @classmethod
+    def run_iface_list_upper(cls, ifupdownobj, ifacenames,
+                       ops, parent=None, followdependents=True,
+                       continueonfailure=True, skip_root=False):
+        """ Runs interface list """
+
+        for ifacename in ifacenames:
+            try:
+              cls.run_iface_graph_upper(ifupdownobj, ifacename, ops, parent,
+                      followdependents, skip_root)
+            except Exception, e:
+                if ifupdownobj.logger.isEnabledFor(logging.DEBUG):
+                    traceback.print_tb(sys.exc_info()[2])
+                ifupdownobj.logger.warn('%s : %s' %(ifacename, str(e)))
+                pass
+
+    @classmethod
+    def get_sorted_iface_list(cls, ifupdownobj, ifacenames, ops,
+                              dependency_graph, indegrees=None):
+        if len(ifacenames) == 1:
+            return ifacenames
+        # Get a sorted list of all interfaces
+        if not indegrees:
+            indegrees = OrderedDict()
+            for ifacename in dependency_graph.keys():
+                indegrees[ifacename] = ifupdownobj.get_iface_refcnt(ifacename)
+        ifacenames_all_sorted = graph.topological_sort_graphs_all(
+                                        dependency_graph, indegrees)
+        # if ALL was set, return all interfaces
+        if ifupdownobj.ALL:
+            return ifacenames_all_sorted
+
+        # else return ifacenames passed as argument in sorted order
+        ifacenames_sorted = []
+        [ifacenames_sorted.append(ifacename)
+                        for ifacename in ifacenames_all_sorted
+                            if ifacename in ifacenames]
+        return ifacenames_sorted
+
+    @classmethod
+    def sched_ifaces(cls, ifupdownobj, ifacenames, ops,
+                dependency_graph=None, indegrees=None,
+                order=ifaceSchedulerFlags.POSTORDER,
+                followdependents=True):
+        """ Runs iface dependeny graph by visiting all the nodes
+        
+        Parameters:
+        -----------
+        ifupdownobj : ifupdown object (used for getting and updating iface
+                                        object state)
+        dependency_graph : dependency graph in adjacency list
+                            format (contains more than one dependency graph)
+        ops : list of operations to perform eg ['pre-up', 'up', 'post-up']
+
+        indegrees : indegree array if present is used to topologically sort
+                    the graphs in the dependency_graph
+        """
+        #
+        # Algo:
+        # if ALL/auto interfaces are specified,
+        #   - walk the dependency tree in postorder or inorder depending
+        #     on the operation.
+        #     (This is to run interfaces correctly in order)
+        # else:
+        #   - sort iface list if the ifaces belong to a "class"
+        #   - else just run iface list in the order they were specified
+        #
+        # Run any upperifaces if available
+        #
+        followupperifaces = []
+        run_queue = []
+        skip_ifacesort = int(ifupdownobj.config.get('skip_ifacesort', '0'))
+        if not skip_ifacesort and not indegrees:
+            indegrees = OrderedDict()
+            for ifacename in dependency_graph.keys():
+                indegrees[ifacename] = ifupdownobj.get_iface_refcnt(ifacename)
+
+        if not ifupdownobj.ALL:
+            # If there is any interface that does exist, maybe it is a
+            # logical interface and we have to followupperifaces when it
+            # comes up, so get that list.
+            followupperifaces = (True if
+                                    [i for i in ifacenames
+                                        if not ifupdownobj.link_exists(i)]
+                                        else False)
+            if not skip_ifacesort and ifupdownobj.IFACE_CLASS:
+                # sort interfaces only if allow class was specified and
+                # not skip_ifacesort
+                run_queue = cls.get_sorted_iface_list(ifupdownobj, ifacenames,
+                                    ops, dependency_graph, indegrees)
+                if run_queue and 'up' in ops[0]:
+                    run_queue.reverse()
+        else:
+            # if -a is set, we dont really have to sort. We pick the interfaces
+            # that have no parents and 
+            if not skip_ifacesort:
+                sorted_ifacenames = cls.get_sorted_iface_list(ifupdownobj,
+                                            ifacenames, ops, dependency_graph,
+                                            indegrees)
+                if sorted_ifacenames:
+                    # pick interfaces that user asked
+                    # and those that dont have any dependents first
+                    [run_queue.append(ifacename)
+                        for ifacename in sorted_ifacenames
+                            if ifacename in ifacenames and
+                            not indegrees.get(ifacename)]
+                    ifupdownobj.logger.debug('graph roots (interfaces that ' +
+                            'dont have dependents):' + ' %s' %str(run_queue))
+                else:
+                    ifupdownobj.logger.warn('interface sort returned None')
+
+        # If queue not present, just run interfaces that were asked by the user
+        if not run_queue:
+            run_queue = list(ifacenames)
+            if 'down' in ops[0]:
+                run_queue.reverse()
+
+        # run interface list
+        ifupdownobj.logger.info('running interfaces: %s' %str(run_queue))
+        cls.run_iface_list(ifupdownobj, run_queue, ops,
+                           parent=None, order=order,
+                           followdependents=followdependents)
+        if not cls._SCHED_RETVAL:
+            raise Exception()
+
+        if (ifupdownobj.config.get('skip_upperifaces', '0') == '0' and
+                ((not ifupdownobj.ALL and followdependents) or
+                followupperifaces) and
+                'up' in ops[0]):
+            # If user had given a set of interfaces to bring up
+            # try and execute 'up' on the upperifaces
+            ifupdownobj.logger.info('running upperifaces (parent interfaces) ' +
+                                    'if available ..')
+            cls._STATE_CHECK = False
+            cls.run_iface_list_upper(ifupdownobj, ifacenames, ops,
+                                     skip_root=True)
+            cls._STATE_CHECK = True
diff --git a/ifupdown/statemanager.py b/ifupdown/statemanager.py
new file mode 100644 (file)
index 0000000..ef9ca7f
--- /dev/null
@@ -0,0 +1,176 @@
+#!/usr/bin/python
+#
+# Copyright 2014 Cumulus Networks, Inc. All rights reserved.
+# Author: Roopa Prabhu, roopa@cumulusnetworks.com
+#
+# stateManager --
+#    interface state manager
+#
+import cPickle
+from collections import OrderedDict
+import logging
+import os
+from iface import *
+
+class pickling():
+    """ class with helper methods for pickling/unpickling iface objects """
+
+    @classmethod
+    def save(cls, filename, list_of_objects):
+        """ pickle a list of iface objects """
+        try:
+            with open(filename, 'w') as f:
+                for obj in list_of_objects:
+                    cPickle.dump(obj, f, cPickle.HIGHEST_PROTOCOL)
+        except:
+            raise
+
+    @classmethod
+    def save_obj(cls, f, obj):
+        """ pickle iface object """
+        try:
+            cPickle.dump(obj, f, cPickle.HIGHEST_PROTOCOL)
+        except:
+            raise
+
+    @classmethod
+    def load(cls, filename):
+        """ load picked iface object """
+        with open(filename, 'r') as f:
+            while True:
+                try: yield cPickle.load(f)
+                except EOFError: break
+                except: raise
+
+class stateManager():
+    """ state manager for managing ifupdown iface obj state
+
+    ifupdown2 has to maitain old objects for down operation on
+    interfaces. ie to down or delete old configuration.
+
+    This class uses pickle to store iface objects.
+
+    """
+
+    state_dir = '/var/tmp/network/'
+    """directory where the state file is stored """
+
+    state_filename = 'ifstatenew'
+    """name of the satefile """
+
+    def __init__(self):
+        """ Initializes statemanager internal state
+
+        which includes a dictionary of last pickled iface objects
+        """
+        self.ifaceobjdict = OrderedDict()
+        self.logger = logging.getLogger('ifupdown.' +
+                    self.__class__.__name__)
+        if not os.path.exists(self.state_dir):
+            os.mkdir(self.state_dir)
+        self.state_file = self.state_dir + self.state_filename
+
+    def save_ifaceobj(self, ifaceobj):
+        self.ifaceobjdict.setdefault(ifaceobj.name,
+                            []).append(ifaceobj)
+
+    def read_saved_state(self, filename=None):
+        """This member function reads saved iface objects
+
+        Kwargs:
+            filename (str): name of the state file
+        """
+
+        pickle_filename = filename
+        if not pickle_filename:
+            pickle_filename = self.state_file
+        if not os.path.exists(pickle_filename):
+            return
+        for ifaceobj in pickling.load(pickle_filename):
+            self.save_ifaceobj(ifaceobj)
+
+    def get_ifaceobjs(self, ifacename):
+        return self.ifaceobjdict.get(ifacename)
+
+    def ifaceobj_sync(self, ifaceobj, op):
+        """This member function sync's new obj state to old statemanager state
+
+        Args:
+            ifaceobj (object): new iface object
+            op (str): ifupdown operation
+        """
+
+        self.logger.debug('%s: statemanager sync state %s'
+                          %(ifaceobj.name, op))
+        old_ifaceobjs = self.ifaceobjdict.get(ifaceobj.name)
+        if 'up' in op:
+            if not old_ifaceobjs:
+                self.ifaceobjdict[ifaceobj.name] = [ifaceobj]
+            else:
+                # If it matches any of the object, return
+                if any(o.compare(ifaceobj) for o in old_ifaceobjs):
+                    return
+                # If it does not match any of the objects, and if
+                # all objs in the list came from the pickled file,
+                # then reset the list and add this object as a fresh one,
+                # else append to the list
+                if old_ifaceobjs[0].flags & iface._PICKLED:
+                    del self.ifaceobjdict[ifaceobj.name]
+                    self.ifaceobjdict[ifaceobj.name] = [ifaceobj]
+                else:
+                    self.ifaceobjdict[ifaceobj.name].append(ifaceobj)
+        elif 'down' in op:
+            # If down of object successfull, delete object from state manager
+            if not old_ifaceobjs:
+                return
+            if ifaceobj.status != ifaceStatus.SUCCESS:
+                return
+            # If it matches any of the object, return
+            oidx = 0
+            for o in old_ifaceobjs:
+                if o.compare(ifaceobj):
+                    old_ifaceobjs.pop(oidx)
+                    if not len(old_ifaceobjs):
+                        del self.ifaceobjdict[ifaceobj.name]
+                    return
+                oidx += 1
+
+    def save_state(self):
+        """ saves state (ifaceobjects) to persistent state file """
+
+        try:
+            with open(self.state_file, 'w') as f:
+                if not len(self.ifaceobjdict):
+                    f.truncate(0)
+                    return
+                self.logger.debug('saving state ..')
+                for ifaceobjs in self.ifaceobjdict.values():
+                    [pickling.save_obj(f, i) for i in ifaceobjs]
+        except:
+            raise
+
+    def dump_pretty(self, ifacenames, format='native'):
+        if not ifacenames:
+            ifacenames = self.ifaceobjdict.keys()
+        for i in ifacenames:
+            ifaceobjs = self.get_ifaceobjs(i)
+            if not ifaceobjs:
+                continue
+            for ifaceobj in ifaceobjs:
+                if format == 'json':
+                    ifaceobj.dump_json()
+                else:
+                    ifaceobj.dump_pretty()
+
+    def dump(self, ifacenames=None):
+        self.logger.debug('statemanager iface state:')
+        if ifacenames:
+            for i in ifacenames:
+                ifaceobj = self.ifaces.get(i)
+                if ifaceobj is None:
+                    raise ifaceNotFoundError('ifname %s'
+                        %i + ' not found')
+                ifaceobj.dump(self.logger)
+        else:
+            for ifacename, ifaceobjs in self.ifaceobjdict.items():
+                [i.dump(self.logger) for i in ifaceobjs]
diff --git a/ifupdown/template.py b/ifupdown/template.py
new file mode 100644 (file)
index 0000000..f1792cc
--- /dev/null
@@ -0,0 +1,59 @@
+#!/usr/bin/python
+#
+# Copyright 2014 Cumulus Networks, Inc. All rights reserved.
+# Author: Roopa Prabhu, roopa@cumulusnetworks.com
+#
+# template --
+#    helper class to render templates
+#
+
+import logging
+import traceback
+from utils import *
+
+class templateEngine():
+    """ provides template rendering methods """
+
+    def __init__(self, template_engine, template_lookuppath=None):
+        self.logger = logging.getLogger('ifupdown.' +
+                    self.__class__.__name__)
+        self.tclass = None
+        self.tclassargs = {}
+        self.render = self._render_default
+        if template_engine == 'mako':
+            try:
+                self.tclass = utils.importName('mako.template', 'Template')
+            except Exception, e:
+                self.logger.warn('unable to load template engine %s (%s)'
+                        %(template_engine, str(e)))
+                pass
+            if template_lookuppath:
+                try:
+                    self.logger.debug('setting template lookuppath to %s'
+                            %template_lookuppath)
+                    lc = utils.importName('mako.lookup', 'TemplateLookup')
+                    self.tclassargs['lookup'] = lc(
+                                directories=template_lookuppath.split(':'))
+                except Exception, e:
+                    self.logger.warn('unable to set template lookup path' +
+                                ' %s (%s)' %(template_lookuppath, str(e)))
+                    pass
+            self.render = self._render_mako
+        else:
+            self.logger.info('skip template processing.., ' +
+                    'template engine not found')
+
+    def _render_default(self, textdata):
+        return textdata
+
+    def _render_mako(self, textdata):
+        """ render textdata passed as argument using mako
+
+        Returns rendered textdata """
+
+        if not self.tclass:
+            return textdata
+        self.logger.info('template processing on interfaces file ...')
+        t = self.tclass(text=textdata, output_encoding='utf-8',
+                     lookup=self.tclassargs.get('lookup'))
+        return t.render()
diff --git a/ifupdown/utils.py b/ifupdown/utils.py
new file mode 100644 (file)
index 0000000..caf6583
--- /dev/null
@@ -0,0 +1,52 @@
+#!/usr/bin/python
+#
+# Copyright 2014 Cumulus Networks, Inc. All rights reserved.
+# Author: Roopa Prabhu, roopa@cumulusnetworks.com
+#
+# utils --
+#    helper class
+#
+import os
+import fcntl
+import re
+
+class utils():
+
+    @classmethod
+    def importName(cls, modulename, name):
+        """ Import a named object """
+        try:
+            module = __import__(modulename, globals(), locals(), [name])
+        except ImportError:
+            return None
+        return getattr(module, name)
+
+    @classmethod
+    def lockFile(cls, lockfile):
+        try:
+            fp = os.open(lockfile, os.O_CREAT | os.O_TRUNC | os.O_WRONLY)
+            fcntl.flock(fp, fcntl.LOCK_EX | fcntl.LOCK_NB)
+        except IOError:
+            return False
+        return True
+
+    @classmethod
+    def parse_iface_range(cls, name):
+        range_match = re.match("^([\w\.]+)\[([\d]+)-([\d]+)\]", name)
+        if range_match:
+            range_groups = range_match.groups()
+            if range_groups[1] and range_groups[2]:
+                return (range_groups[0], int(range_groups[1], 10),
+                        int(range_groups[2], 10))
+        return None
+
+    @classmethod
+    def expand_iface_range(cls, name):
+        ifacenames = []
+        iface_range = cls.parse_iface_range(name)
+        if iface_range:
+            for i in range(iface_range[1], iface_range[2]):
+                ifacenames.append('%s-%d' %(iface_range[0], i))
+        return ifacenames
+
+
diff --git a/ifupdown2/KNOWN_ISSUES b/ifupdown2/KNOWN_ISSUES
deleted file mode 100644 (file)
index bcc3a4e..0000000
+++ /dev/null
@@ -1,6 +0,0 @@
-- There is a state issue if multiple configuration blocks are present for the same interface in the interfaces file
-- `ifquery -r` can give wrong result if dhclient is running + static addresses are configured
-- `ifquery -r` status is success for success case and also for cases where there
-is no support for query yet
-- setup.py has ifupdown listed in data section instead of scripts: This is because default location for scripts is /usr/bin/. And ifupdown default location is /sbin. With newer versions we can specify --install-scripts directory. This needs to be fixed then.
-- and more :)
diff --git a/ifupdown2/LICENSE b/ifupdown2/LICENSE
deleted file mode 100644 (file)
index 22fbe5d..0000000
+++ /dev/null
@@ -1,339 +0,0 @@
-GNU GENERAL PUBLIC LICENSE
-                       Version 2, June 1991
-
- Copyright (C) 1989, 1991 Free Software Foundation, Inc., <http://fsf.org/>
- 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
- Everyone is permitted to copy and distribute verbatim copies
- of this license document, but changing it is not allowed.
-
-                            Preamble
-
-  The licenses for most software are designed to take away your
-freedom to share and change it.  By contrast, the GNU General Public
-License is intended to guarantee your freedom to share and change free
-software--to make sure the software is free for all its users.  This
-General Public License applies to most of the Free Software
-Foundation's software and to any other program whose authors commit to
-using it.  (Some other Free Software Foundation software is covered by
-the GNU Lesser 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.
-
-    {description}
-    Copyright (C) {year}  {fullname}
-
-    This program is free software; you can redistribute it and/or modify
-    it under the terms of the GNU General Public License as published by
-    the Free Software Foundation; either version 2 of the License, or
-    (at your option) any later version.
-
-    This program is distributed in the hope that it will be useful,
-    but WITHOUT ANY WARRANTY; without even the implied warranty of
-    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-    GNU General Public License for more details.
-
-    You should have received a copy of the GNU General Public License along
-    with this program; if not, write to the Free Software Foundation, Inc.,
-    51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
-
-Also add information on how to contact you by electronic and paper mail.
-
-If the program is interactive, make it output a short notice like this
-when it starts in an interactive mode:
-
-    Gnomovision version 69, Copyright (C) year name of author
-    Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
-    This is free software, and you are welcome to redistribute it
-    under certain conditions; type `show c' for details.
-
-The hypothetical commands `show w' and `show c' should show the appropriate
-parts of the General Public License.  Of course, the commands you use may
-be called something other than `show w' and `show c'; they could even be
-mouse-clicks or menu items--whatever suits your program.
-
-You should also get your employer (if you work as a programmer) or your
-school, if any, to sign a "copyright disclaimer" for the program, if
-necessary.  Here is a sample; alter the names:
-
-  Yoyodyne, Inc., hereby disclaims all copyright interest in the program
-  `Gnomovision' (which makes passes at compilers) written by James Hacker.
-
-  {signature of Ty Coon}, 1 April 1989
-  Ty Coon, President of Vice
-
-This General Public License does not permit incorporating your program into
-proprietary programs.  If your program is a subroutine library, you may
-consider it more useful to permit linking proprietary applications with the
-library.  If this is what you want to do, use the GNU Lesser General
-Public License instead of this License.
\ No newline at end of file
diff --git a/ifupdown2/README.rst b/ifupdown2/README.rst
deleted file mode 100644 (file)
index 6187ec0..0000000
+++ /dev/null
@@ -1,74 +0,0 @@
-python-ifupdown2
-================
-
-This package is a replacement for the debian ifupdown package.
-It is ifupdown re-written in python. It maintains the original ifupdown
-pluggable architecture and extends it further.
-
-The python-ifupdown2 package provides the infrastructure for
-parsing /etc/network/interfaces file, loading, scheduling and state
-management of interfaces.
-
-It dynamically loads python modules from /usr/share/ifupdownaddons.
-To remain compatible with other packages that depend on ifupdown,
-it also executes scripts under /etc/network/.
-To make the transition smoother, a python module under
-/usr/share/ifupdownaddons will override a script by the same name under
-/etc/network/.
-
-It publishes an interface object which is passed to all loadble python
-modules. For more details on adding a addon module, see the section on
-adding python modules.
-
-
-pluggable python modules:
-=========================
-Unlike original ifupdown, all interface configuration is moved to external
-python modules. That includes inet, inet6 and dhcp configurations.
-
-A set of default modules are included in the package.
-
-python-ifupdown2 expects a few things from the pluggable modules:
-- the module should implement a class by the same name
-- the interface object (class iface) and the operation to be performed is
-  passed to the modules
-- the python addon class should provide a few methods:
-       - run() : method to configure the interface.
-       - get_ops() : must return a list of operations it supports.
-               eg: 'pre-up', 'post-down'
-       - get_dependent_ifacenames() : must return a list of interfaces the
-         interface is dependent on. This is used to build the dependency list
-         for sorting and executing interfaces in dependency order.
-       - if the module supports -r option to ifquery, ie ability to construct the
-      ifaceobj from running state, it can optionally implement the
-      get_dependent_ifacenames_running() method, to return the list of
-      dependent interfaces derived from running state of the interface.
-      This is different from get_dependent_ifacenames() where the dependent
-      interfaces are derived from the interfaces config file (provided by the
-      user).
-
-Example: Address handling module /usr/share/ifupdownaddons/address.py
-
-
-build
-=====
-- get source
-
-- install build dependencies:
-    apt-get install python-stdeb
-    apt-get install python-docutils
-
-- cd <python-ifupdown2 sourcedir> && ./build.sh
-
-  (generates python-ifupdown2-<ver>.deb)
-
-install
-=======
-
-- remove existing ifupdown package
-  dpkg -r ifupdown
-
-- install python-ifupdown2 using `dpkg -i`
-
-- or install from deb
-    dpkg -i python-ifupdown2-<ver>.deb
diff --git a/ifupdown2/TODO b/ifupdown2/TODO
deleted file mode 100644 (file)
index aff9cd5..0000000
+++ /dev/null
@@ -1,36 +0,0 @@
-TODO:
-====
-- support old ifupdown state file /run/network/ifstate. Because some app's seem to use it
-- support for debian ifupdown methods: tunnel, v4tunnel, 6to4, ppp, wvdial, ipv4ll
-- support for debian ifupdown ipv6 auto method
-- support for debian ifupdown CAN address family
-- Compat : support for LOGICAL interfaces
-- dry-run improvement: It skips the cache completely. Which means It tells you the commands it would execute if the system is clean. Its not smart enought to say what it will really execute given the state of the system
-
-- Ifquery does not report link status, mainly because it reports only in terms of /etc/network/interfaces attributes. Plan to fix that
-- more Documentation
-- Priorities for addon modules
-- have ability to also run uninstall on interfaces that dont have any config
-- ifup hotplug support (basically needs some testing and fixing broken things)
-- -q quiet option
-- support for /etc/networking.defaults
-- implement legacy ifupdown mapping feature
-- support for the following ifupdown options:
-    -o OPTION=VALUE     set OPTION to VALUE as though it were in
-                        /etc/network/interfaces
-    --no-mappings       don't run any mappings
-    --no-scripts        don't run any hook scripts
-- parallel implementation
-- Test all original ifupdown options for compatibility
-- Test with ifupdown-extra, ifmetric, ifupdown-scripts-zg2
-- export other environment variables to bash scripts (for backward compatibility):
-       IFACE  physical name of the interface being processed
-        LOGICAL logical name of the interface being processed
-        ADDRFAM address family of the interface
-        METHOD method of the interface (e.g., static)
-        MODE   start if run from ifup, stop if run from ifdown
-        PHASE  as per MODE, but with finer granularity, distinguishing the pre-
-               up, post-up, pre-down and post-down phases.
-        VERBOSITY indicates  whether --verbose was used; set to 1 if so, 0 if not.
-        PATH   the  command   search   path:   /usr/local/sbin:/usr/local/bin:‐
-               /usr/sbin:/usr/bin:/sbin:/bin
diff --git a/ifupdown2/addons/address.py b/ifupdown2/addons/address.py
deleted file mode 100644 (file)
index 8d9bb75..0000000
+++ /dev/null
@@ -1,394 +0,0 @@
-#!/usr/bin/python
-#
-# Copyright 2014 Cumulus Networks, Inc. All rights reserved.
-# Author: Roopa Prabhu, roopa@cumulusnetworks.com
-#
-
-try:
-    from ipaddr import IPNetwork
-    from sets import Set
-    from ifupdown.iface import *
-    from ifupdownaddons.modulebase import moduleBase
-    from ifupdownaddons.iproute2 import iproute2
-    from ifupdownaddons.dhclient import dhclient
-except ImportError, e:
-    raise ImportError (str(e) + "- required module not found")
-
-class address(moduleBase):
-    """  ifupdown2 addon module to configure address, mtu, hwaddress, alias
-    (description) on an interface """
-
-    _modinfo = {'mhelp' : 'address configuration module for interfaces',
-                'attrs': {
-                      'address' :
-                            {'help' : 'ipv4 or ipv6 addresses',
-                             'example' : ['address 10.0.12.3/24',
-                             'address 2000:1000:1000:1000:3::5/128']},
-                      'netmask' :
-                            {'help': 'netmask',
-                             'example' : ['netmask 255.255.255.0'],
-                             'compat' : True},
-                      'broadcast' :
-                            {'help': 'broadcast address',
-                             'example' : ['broadcast 10.0.1.255']},
-                      'scope' :
-                            {'help': 'scope',
-                             'example' : ['scope host']},
-                      'preferred-lifetime' :
-                            {'help': 'preferred lifetime',
-                             'example' : ['preferred-lifetime forever',
-                                          'preferred-lifetime 10']},
-                      'gateway' :
-                            {'help': 'default gateway',
-                             'example' : ['gateway 255.255.255.0']},
-                      'mtu' :
-                            { 'help': 'interface mtu',
-                              'example' : ['mtu 1600'],
-                              'default' : '1500'},
-                      'hwaddress' :
-                            {'help' : 'hw address',
-                             'example': ['hwaddress 44:38:39:00:27:b8']},
-                      'alias' :
-                            { 'help': 'description/alias',
-                              'example' : ['alias testnetwork']},
-                      'address-purge' :
-                            { 'help': 'purge existing addresses. By default ' +
-                              'any existing ip addresses on an interface are ' +
-                              'purged to match persistant addresses in the ' +
-                              'interfaces file. Set this attribute to \'no\'' +
-                              'if you want to preserve existing addresses',
-                              'default' : 'yes',
-                              'example' : ['address-purge yes/no']}}}
-
-    def __init__(self, *args, **kargs):
-        moduleBase.__init__(self, *args, **kargs)
-        self.ipcmd = None
-        self._bridge_fdb_query_cache = {}
-
-    def _address_valid(self, addrs):
-        if not addrs:
-           return False
-        if any(map(lambda a: True if a[:7] != '0.0.0.0'
-                else False, addrs)):
-           return True
-        return False
-
-    def _process_bridge(self, ifaceobj, up):
-        hwaddress = ifaceobj.get_attr_value_first('hwaddress')
-        addrs = ifaceobj.get_attr_value_first('address')
-        is_vlan_dev_on_vlan_aware_bridge = False
-        is_bridge = self.ipcmd.is_bridge(ifaceobj.name)
-        if not is_bridge:
-            if '.' in ifaceobj.name:
-                (bridgename, vlan) = ifaceobj.name.split('.')
-                is_vlan_dev_on_vlan_aware_bridge = self.ipcmd.bridge_is_vlan_aware(bridgename)
-        if ((is_bridge and not self.ipcmd.bridge_is_vlan_aware(ifaceobj.name))
-                        or is_vlan_dev_on_vlan_aware_bridge):
-           if self._address_valid(addrs):
-              if up:
-                self.write_file('/proc/sys/net/ipv4/conf/%s' %ifaceobj.name +
-                                '/arp_accept', '1')
-              else:
-                self.write_file('/proc/sys/net/ipv4/conf/%s' %ifaceobj.name +
-                                '/arp_accept', '0')
-        if hwaddress and is_vlan_dev_on_vlan_aware_bridge:
-           if up:
-              self.ipcmd.bridge_fdb_add(bridgename, hwaddress, vlan)
-           else:
-              self.ipcmd.bridge_fdb_del(bridgename, hwaddress, vlan)
-
-    def _inet_address_config(self, ifaceobj):
-        purge_addresses = ifaceobj.get_attr_value_first('address-purge')
-        if not purge_addresses:
-           purge_addresses = 'yes'
-        newaddrs = []
-        addrs = ifaceobj.get_attr_value('address')
-        if addrs:
-            if ifaceobj.role & ifaceRole.SLAVE:
-                # we must not configure an IP address if the interface is enslaved
-                self.log_warn('interface %s is enslaved and cannot have an IP Address' % \
-                              (ifaceobj.name))
-                return
-            # If user address is not in CIDR notation, convert them to CIDR
-            for addr_index in range(0, len(addrs)):
-                addr = addrs[addr_index]
-                if '/' in addr:
-                    newaddrs.append(addr)
-                    continue
-                netmask = ifaceobj.get_attr_value_n('netmask', addr_index)
-                if netmask:
-                    prefixlen = IPNetwork('%s' %addr +
-                                '/%s' %netmask).prefixlen
-                    newaddrs.append(addr + '/%s' %prefixlen)
-                else:
-                    newaddrs.append(addr)
-
-        if (not self.PERFMODE and
-                not (ifaceobj.flags & iface.HAS_SIBLINGS) and
-                purge_addresses == 'yes'):
-            # if perfmode is not set and also if iface has no sibling
-            # objects, purge addresses that are not present in the new
-            # config
-            runningaddrs = self.ipcmd.addr_get(ifaceobj.name, details=False)
-            if newaddrs == runningaddrs:
-                return
-            try:
-                # if primary address is not same, there is no need to keep any.
-                # reset all addresses
-                if (newaddrs and runningaddrs and
-                        (newaddrs[0] != runningaddrs[0])):
-                    self.ipcmd.del_addr_all(ifaceobj.name)
-                else:
-                    self.ipcmd.del_addr_all(ifaceobj.name, newaddrs)
-            except Exception, e:
-                self.log_warn(str(e))
-        if not newaddrs:
-            return
-        for addr_index in range(0, len(newaddrs)):
-            try:
-                self.ipcmd.addr_add(ifaceobj.name, newaddrs[addr_index],
-                    ifaceobj.get_attr_value_n('broadcast', addr_index),
-                    ifaceobj.get_attr_value_n('pointopoint',addr_index),
-                    ifaceobj.get_attr_value_n('scope', addr_index),
-                    ifaceobj.get_attr_value_n('preferred-lifetime', addr_index))
-            except Exception, e:
-                self.log_error(str(e))
-
-    def _up(self, ifaceobj):
-        if not self.ipcmd.link_exists(ifaceobj.name):
-            return
-        addr_method = ifaceobj.addr_method
-        try:
-            # release any stale dhcp addresses if present
-            if (addr_method != "dhcp" and not self.PERFMODE and
-                    not (ifaceobj.flags & iface.HAS_SIBLINGS)):
-                # if not running in perf mode and ifaceobj does not have
-                # any sibling iface objects, kill any stale dhclient
-                # processes
-                dhclientcmd = dhclient()
-                if dhclient.is_running(ifaceobj.name):
-                    # release any dhcp leases
-                    dhclientcmd.release(ifaceobj.name)
-                elif dhclient.is_running6(ifaceobj.name):
-                    dhclientcmd.release6(ifaceobj.name)
-        except:
-            pass
-
-        self.ipcmd.batch_start()
-        if addr_method != "dhcp":
-            self._inet_address_config(ifaceobj)
-        mtu = ifaceobj.get_attr_value_first('mtu')
-        if mtu:
-           self.ipcmd.link_set(ifaceobj.name, 'mtu', mtu)
-        alias = ifaceobj.get_attr_value_first('alias')
-        if alias:
-           self.ipcmd.link_set_alias(ifaceobj.name, alias)
-        hwaddress = ifaceobj.get_attr_value_first('hwaddress')
-        if hwaddress:
-            self.ipcmd.link_set(ifaceobj.name, 'address', hwaddress)
-        self.ipcmd.batch_commit()
-
-        try:
-            # Handle special things on a bridge
-            self._process_bridge(ifaceobj, True)
-        except Exception, e:
-            self.log_warn('%s: %s' %(ifaceobj.name, str(e)))
-            pass
-
-        if addr_method != "dhcp":
-            self.ipcmd.route_add_gateway(ifaceobj.name,
-                    ifaceobj.get_attr_value_first('gateway'))
-
-    def _down(self, ifaceobj):
-        try:
-            if not self.ipcmd.link_exists(ifaceobj.name):
-                return
-            addr_method = ifaceobj.addr_method
-            if addr_method != "dhcp":
-                self.ipcmd.route_del_gateway(ifaceobj.name,
-                    ifaceobj.get_attr_value_first('gateway'),
-                    ifaceobj.get_attr_value_first('metric'))
-                self.ipcmd.del_addr_all(ifaceobj.name)
-            alias = ifaceobj.get_attr_value_first('alias')
-            if alias:
-                self.ipcmd.link_set(ifaceobj.name, 'alias', "\'\'")
-            # XXX hwaddress reset cannot happen because we dont know last
-            # address.
-
-            # Handle special things on a bridge
-            self._process_bridge(ifaceobj, False)
-        except Exception, e:
-            self.logger.debug('%s : %s' %(ifaceobj.name, str(e)))
-            pass
-
-    def _get_iface_addresses(self, ifaceobj):
-        addrlist = ifaceobj.get_attr_value('address')
-        outaddrlist = []
-
-        if not addrlist: return None
-        for addrindex in range(0, len(addrlist)):
-            addr = addrlist[addrindex]
-            netmask = ifaceobj.get_attr_value_n('netmask', addrindex)
-            if netmask:
-                prefixlen = IPNetwork('%s' %addr +
-                                '/%s' %netmask).prefixlen
-                addr = addr + '/%s' %prefixlen
-            outaddrlist.append(addr)
-        return outaddrlist
-
-    def _get_bridge_fdbs(self, bridgename, vlan):
-        fdbs = self._bridge_fdb_query_cache.get(bridgename)
-        if not fdbs:
-           fdbs = self.ipcmd.bridge_fdb_show_dev(bridgename)
-           if not fdbs:
-              return
-           self._bridge_fdb_query_cache[bridgename] = fdbs
-        return fdbs.get(vlan)
-
-    def _check_addresses_in_bridge(self, ifaceobj, hwaddress):
-        """ If the device is a bridge, make sure the addresses
-        are in the bridge """
-        if '.' in ifaceobj.name:
-            (bridgename, vlan) = ifaceobj.name.split('.')
-            if self.ipcmd.bridge_is_vlan_aware(bridgename):
-                fdb_addrs = self._get_bridge_fdbs(bridgename, vlan)
-                if not fdb_addrs or hwaddress not in fdb_addrs:
-                   return False
-        return True
-
-    def _query_check(self, ifaceobj, ifaceobjcurr):
-        runningaddrsdict = None
-        if not self.ipcmd.link_exists(ifaceobj.name):
-            self.logger.debug('iface %s not found' %ifaceobj.name)
-            return
-        addr_method = ifaceobj.addr_method
-        self.query_n_update_ifaceobjcurr_attr(ifaceobj, ifaceobjcurr,
-                'mtu', self.ipcmd.link_get_mtu)
-        hwaddress = ifaceobj.get_attr_value_first('hwaddress')
-        if hwaddress:
-            rhwaddress = self.ipcmd.link_get_hwaddress(ifaceobj.name)
-            if not rhwaddress  or rhwaddress != hwaddress:
-               ifaceobjcurr.update_config_with_status('hwaddress', rhwaddress,
-                       1)
-            elif not self._check_addresses_in_bridge(ifaceobj, hwaddress):
-               # XXX: hw address is not in bridge
-               ifaceobjcurr.update_config_with_status('hwaddress', rhwaddress,
-                       1)
-               ifaceobjcurr.status_str = 'bridge fdb error'
-            else:
-               ifaceobjcurr.update_config_with_status('hwaddress', rhwaddress,
-                       0)
-        self.query_n_update_ifaceobjcurr_attr(ifaceobj, ifaceobjcurr,
-                    'alias', self.ipcmd.link_get_alias)
-        # compare addresses
-        if addr_method == 'dhcp':
-           return
-        addrs = self._get_iface_addresses(ifaceobj)
-        runningaddrsdict = self.ipcmd.addr_get(ifaceobj.name)
-
-        # Set ifaceobjcurr method and family
-        ifaceobjcurr.addr_method = ifaceobj.addr_method
-        ifaceobjcurr.addr_family = ifaceobj.addr_family
-        if not runningaddrsdict and not addrs:
-            return
-        runningaddrs = runningaddrsdict.keys() if runningaddrsdict else []
-        if runningaddrs != addrs:
-            runningaddrsset = set(runningaddrs) if runningaddrs else set([])
-            addrsset = set(addrs) if addrs else set([])
-            if (ifaceobj.flags & iface.HAS_SIBLINGS):
-                if not addrsset:
-                    return
-                # only check for addresses present in running config
-                addrsdiff = addrsset.difference(runningaddrsset)
-                for addr in addrs:
-                    if addr in addrsdiff:
-                        ifaceobjcurr.update_config_with_status('address',
-                                    addr, 1)
-                    else:
-                        ifaceobjcurr.update_config_with_status('address',
-                                    addr, 0)
-            else:
-                addrsdiff = addrsset.symmetric_difference(runningaddrsset)
-                for addr in addrsset.union(runningaddrsset):
-                    if addr in addrsdiff:
-                        ifaceobjcurr.update_config_with_status('address',
-                                                               addr, 1)
-                    else:
-                        ifaceobjcurr.update_config_with_status('address',
-                                                               addr, 0)
-        elif addrs:
-            [ifaceobjcurr.update_config_with_status('address',
-                       addr, 0) for addr in addrs]
-        #XXXX Check broadcast address, scope, etc
-        return
-
-    def _query_running(self, ifaceobjrunning):
-        if not self.ipcmd.link_exists(ifaceobjrunning.name):
-            self.logger.debug('iface %s not found' %ifaceobjrunning.name)
-            return
-        dhclientcmd = dhclient()
-        if (dhclientcmd.is_running(ifaceobjrunning.name) or
-                dhclientcmd.is_running6(ifaceobjrunning.name)):
-            # If dhcp is configured on the interface, we skip it
-            return 
-        isloopback = self.ipcmd.link_isloopback(ifaceobjrunning.name)
-        if isloopback:
-            default_addrs = ['127.0.0.1/8', '::1/128']
-            ifaceobjrunning.addr_family = 'inet'
-            ifaceobjrunning.addr_method = 'loopback'
-        else:
-            default_addrs = []
-        runningaddrsdict = self.ipcmd.addr_get(ifaceobjrunning.name)
-        if runningaddrsdict:
-            [ifaceobjrunning.update_config('address', addr)
-                for addr, addrattrs in runningaddrsdict.items()
-                if addr not in default_addrs]
-        mtu = self.ipcmd.link_get_mtu(ifaceobjrunning.name)
-        if (mtu and
-                (ifaceobjrunning.name == 'lo' and mtu != '16436') or
-                (ifaceobjrunning.name != 'lo' and
-                    mtu != self.get_mod_subattr('mtu', 'default'))):
-                ifaceobjrunning.update_config('mtu', mtu)
-        alias = self.ipcmd.link_get_alias(ifaceobjrunning.name)
-        if alias: 
-            ifaceobjrunning.update_config('alias', alias)
-
-    _run_ops = {'up' : _up,
-               'down' : _down,
-               'query-checkcurr' : _query_check,
-               'query-running' : _query_running }
-
-    def get_ops(self):
-        """ returns list of ops supported by this module """
-        return self._run_ops.keys()
-
-    def _init_command_handlers(self):
-        if not self.ipcmd:
-            self.ipcmd = iproute2(**self.get_flags())
-
-    def run(self, ifaceobj, operation, query_ifaceobj=None, **extra_args):
-        """ run address configuration on the interface object passed as argument
-
-        Args:
-            **ifaceobj** (object): iface object
-
-            **operation** (str): any of 'up', 'down', 'query-checkcurr',
-                                 'query-running'
-        Kwargs:
-            query_ifaceobj (object): query check ifaceobject. This is only
-                valid when op is 'query-checkcurr'. It is an object same as
-                ifaceobj, but contains running attribute values and its config
-                status. The modules can use it to return queried running state
-                of interfaces. status is success if the running state is same
-                as user required state in ifaceobj. error otherwise.
-        """
-        if ifaceobj.type == ifaceType.BRIDGE_VLAN:
-           return
-        op_handler = self._run_ops.get(operation)
-        if not op_handler:
-            return
-        self._init_command_handlers()
-        if operation == 'query-checkcurr':
-            op_handler(self, ifaceobj, query_ifaceobj)
-        else:
-            op_handler(self, ifaceobj)
diff --git a/ifupdown2/addons/addressvirtual.py b/ifupdown2/addons/addressvirtual.py
deleted file mode 100644 (file)
index 98ac536..0000000
+++ /dev/null
@@ -1,321 +0,0 @@
-#!/usr/bin/python
-#
-# Copyright 2014 Cumulus Networks, Inc. All rights reserved.
-# Author: Roopa Prabhu, roopa@cumulusnetworks.com
-#
-
-from ifupdown.iface import *
-from ifupdownaddons.modulebase import moduleBase
-from ifupdownaddons.iproute2 import iproute2
-import ifupdown.rtnetlink_api as rtnetlink_api
-from ipaddr import IPNetwork
-import logging
-import os
-import glob
-
-class addressvirtual(moduleBase):
-    """  ifupdown2 addon module to configure virtual addresses """
-
-    _modinfo = {'mhelp' : 'address module configures virtual addresses for ' +
-                          'interfaces. It creates a macvlan interface for ' +
-                          'every mac ip address-virtual line',
-                'attrs' : {
-                    'address-virtual' :
-                        { 'help' : 'bridge router virtual mac and ip',
-                          'example' : ['address-virtual 00:11:22:33:44:01 11.0.1.254/24 11.0.1.254/24']}
-                 }}
-
-
-    def __init__(self, *args, **kargs):
-        moduleBase.__init__(self, *args, **kargs)
-        self.ipcmd = None
-        self._bridge_fdb_query_cache = {}
-
-    def _is_supported(self, ifaceobj):
-        if ifaceobj.get_attr_value_first('address-virtual'):
-            return True
-        return False
-
-    def _get_macvlan_prefix(self, ifaceobj):
-        return '%s-v' %ifaceobj.name[0:13].replace('.', '-')
-
-    def _add_addresses_to_bridge(self, ifaceobj, hwaddress):
-        # XXX: batch the addresses
-        if '.' in ifaceobj.name:
-            (bridgename, vlan) = ifaceobj.name.split('.')
-            if self.ipcmd.bridge_is_vlan_aware(bridgename):
-                [self.ipcmd.bridge_fdb_add(bridgename, addr,
-                    vlan) for addr in hwaddress]
-        elif self.ipcmd.is_bridge(ifaceobj.name):
-            [self.ipcmd.bridge_fdb_add(ifaceobj.name, addr)
-                    for addr in hwaddress]
-
-    def _remove_addresses_from_bridge(self, ifaceobj, hwaddress):
-        # XXX: batch the addresses
-        bridgename = None
-        if '.' in ifaceobj.name:
-            if self.ipcmd.bridge_is_vlan_aware(bridgename):
-                (bridgename, vlan) = ifaceobj.name.split('.')
-        elif self.ipcmd.is_bridge(ifaceobj.name):
-            vlan = None
-            bridgename = ifaceobj.name
-        if not bridgename:
-            return
-        for addr in hwaddress:
-            try:
-                self.ipcmd.bridge_fdb_del(bridgename, addr, vlan)
-            except Exception, e:
-                self.logger.debug("%s: %s" %(ifaceobj.name, str(e)))
-                pass
-
-    def _get_bridge_fdbs(self, bridgename, vlan):
-        fdbs = self._bridge_fdb_query_cache.get(bridgename)
-        if not fdbs:
-           fdbs = self.ipcmd.bridge_fdb_show_dev(bridgename)
-           if not fdbs:
-              return
-           self._bridge_fdb_query_cache[bridgename] = fdbs
-        return fdbs.get(vlan)
-
-    def _check_addresses_in_bridge(self, ifaceobj, hwaddress):
-        """ If the device is a bridge, make sure the addresses
-        are in the bridge """
-        if '.' in ifaceobj.name:
-            (bridgename, vlan) = ifaceobj.name.split('.')
-            if self.ipcmd.bridge_is_vlan_aware(bridgename):
-                fdb_addrs = self._get_bridge_fdbs(bridgename, vlan)
-                if not fdb_addrs or hwaddress not in fdb_addrs:
-                   return False
-        return True
-
-    def _fix_connected_route(self, ifaceobj, vifacename, addr):
-        #
-        # XXX: Hack to make sure the primary address 
-        # is the first in the routing table.
-        #
-        # We use `ip route get` on the vrr network to see which
-        # device the kernel returns. if it is the mac vlan device,
-        # flap the macvlan device to adjust the routing table entry.
-        # 
-        # flapping the macvlan device makes sure the macvlan
-        # connected route goes through delete + add, hence adjusting
-        # the order in the routing table.
-        #
-        try:
-            self.logger.info('%s: checking route entry ...' %ifaceobj.name)
-            ip = IPNetwork(addr)
-            route_prefix = '%s/%d' %(ip.network, ip.prefixlen)
-
-            dev = self.ipcmd.ip_route_get_dev(route_prefix)
-            if dev and dev == vifacename:
-                self.logger.info('%s: preferred routing entry ' %ifaceobj.name +
-                                 'seems to be of the macvlan dev %s'
-                                 %vifacename +
-                                 ' .. flapping macvlan dev to fix entry.')
-                self.ipcmd.link_down(vifacename)
-                self.ipcmd.link_up(vifacename)
-        except Exception, e:
-            self.logger.debug('%s: fixing route entry failed (%s)'
-                              %str(e))
-            pass
-
-    def _apply_address_config(self, ifaceobj, address_virtual_list):
-        purge_existing = False if self.PERFMODE else True
-
-        hwaddress = []
-        self.ipcmd.batch_start()
-        av_idx = 0
-        macvlan_prefix = self._get_macvlan_prefix(ifaceobj)
-        for av in address_virtual_list:
-            av_attrs = av.split()
-            if len(av_attrs) < 2:
-                self.logger.warn("%s: incorrect address-virtual attrs '%s'"
-                             %(ifaceobj.name,  av))
-                av_idx += 1
-                continue
-
-            # Create a macvlan device on this device and set the virtual
-            # router mac and ip on it
-            link_created = False
-            macvlan_ifacename = '%s%d' %(macvlan_prefix, av_idx)
-            if not self.ipcmd.link_exists(macvlan_ifacename):
-                rtnetlink_api.rtnl_api.create_macvlan(macvlan_ifacename,
-                                                      ifaceobj.name)
-                link_created = True
-            if av_attrs[0] != 'None':
-                self.ipcmd.link_set_hwaddress(macvlan_ifacename, av_attrs[0])
-                hwaddress.append(av_attrs[0])
-            self.ipcmd.addr_add_multiple(macvlan_ifacename, av_attrs[1:],
-                                         purge_existing)
-            # If link existed before, flap the link
-            if not link_created:
-                self._fix_connected_route(ifaceobj, macvlan_ifacename,
-                                          av_attrs[1])
-            av_idx += 1
-        self.ipcmd.batch_commit()
-
-        # if ifaceobj is a bridge and bridge is a vlan aware bridge
-        # add the vid to the bridge
-        self._add_addresses_to_bridge(ifaceobj, hwaddress)
-
-    def _remove_running_address_config(self, ifaceobj):
-        if not self.ipcmd.link_exists(ifaceobj.name):
-            return
-        hwaddress = []
-        self.ipcmd.batch_start()
-        macvlan_prefix = self._get_macvlan_prefix(ifaceobj)
-        for macvlan_ifacename in glob.glob("/sys/class/net/%s-*" %macvlan_prefix):
-            macvlan_ifacename = os.path.basename(macvlan_ifacename)
-            if not self.ipcmd.link_exists(macvlan_ifacename):
-                continue
-            hwaddress.append(self.ipcmd.link_get_hwaddress(macvlan_ifacename))
-            self.ipcmd.link_delete(os.path.basename(macvlan_ifacename))
-            # XXX: Also delete any fdb addresses. This requires, checking mac address
-            # on individual macvlan interfaces and deleting the vlan from that.
-        self.ipcmd.batch_commit()
-        if any(hwaddress):
-            self._remove_addresses_from_bridge(ifaceobj, hwaddress)
-
-    def _remove_address_config(self, ifaceobj, address_virtual_list=None):
-        if not address_virtual_list:
-            self._remove_running_address_config(ifaceobj)
-            return
-
-        if not self.ipcmd.link_exists(ifaceobj.name):
-            return
-        hwaddress = []
-        self.ipcmd.batch_start()
-        av_idx = 0
-        macvlan_prefix = self._get_macvlan_prefix(ifaceobj)
-        for av in address_virtual_list:
-            av_attrs = av.split()
-            if len(av_attrs) < 2:
-                self.logger.warn("%s: incorrect address-virtual attrs '%s'"
-                             %(ifaceobj.name,  av))
-                av_idx += 1
-                continue
-
-            # Delete the macvlan device on this device
-            macvlan_ifacename = '%s%d' %(macvlan_prefix, av_idx)
-            self.ipcmd.link_delete(os.path.basename(macvlan_ifacename))
-            if av_attrs[0] != 'None':
-                hwaddress.append(av_attrs[0])
-            av_idx += 1
-        self.ipcmd.batch_commit()
-        self._remove_addresses_from_bridge(ifaceobj, hwaddress)
-
-    def _up(self, ifaceobj):
-        address_virtual_list = ifaceobj.get_attr_value('address-virtual')
-        if not address_virtual_list:
-            # XXX: address virtual is not present. In which case,
-            # delete stale macvlan devices.
-            self._remove_address_config(ifaceobj, address_virtual_list)
-            return
-
-        if not self.ipcmd.link_exists(ifaceobj.name):
-            return
-        self._apply_address_config(ifaceobj, address_virtual_list)
-
-    def _down(self, ifaceobj):
-        try:
-            self._remove_address_config(ifaceobj,
-                         ifaceobj.get_attr_value('address-virtual'))
-        except Exception, e:
-            self.log_warn(str(e))
-
-    def _query_check(self, ifaceobj, ifaceobjcurr):
-        address_virtual_list = ifaceobj.get_attr_value('address-virtual')
-        if not address_virtual_list:
-            return
-        if not self.ipcmd.link_exists(ifaceobj.name):
-            return
-        av_idx = 0
-        macvlan_prefix = self._get_macvlan_prefix(ifaceobj)
-        for address_virtual in address_virtual_list:
-            av_attrs = address_virtual.split()
-            if len(av_attrs) < 2:
-                self.logger.warn("%s: incorrect address-virtual attrs '%s'"
-                             %(ifaceobj.name,  address_virtual))
-                av_idx += 1
-                continue
-
-            # Check if the macvlan device on this interface
-            macvlan_ifacename = '%s%d' %(macvlan_prefix, av_idx)
-            if not self.ipcmd.link_exists(macvlan_ifacename):
-                ifaceobjcurr.update_config_with_status('address-virtual',
-                            '', 1)
-                av_idx += 1
-                continue
-            # Check mac and ip address
-            rhwaddress = self.ipcmd.link_get_hwaddress(macvlan_ifacename)
-            raddrs = self.ipcmd.addr_get(macvlan_ifacename)
-            if not raddrs or not rhwaddress:
-               ifaceobjcurr.update_config_with_status('address-virtual', '', 1)
-               av_idx += 1
-               continue
-            raddrs = raddrs.keys()
-            if (rhwaddress == av_attrs[0] and raddrs == av_attrs[1:] and
-                    self._check_addresses_in_bridge(ifaceobj, av_attrs[0])):
-               ifaceobjcurr.update_config_with_status('address-virtual',
-                            address_virtual, 0)
-            else:
-               raddress_virtual = '%s %s' %(rhwaddress, ' '.join(raddrs))
-               ifaceobjcurr.update_config_with_status('address-virtual',
-                            raddress_virtual, 1)
-            av_idx += 1
-        return
-
-    def _query_running(self, ifaceobjrunning):
-        macvlan_prefix = self._get_macvlan_prefix(ifaceobjrunning)
-        address_virtuals = glob.glob("/sys/class/net/%s*" %macvlan_prefix)
-        for av in address_virtuals:
-            macvlan_ifacename = os.path.basename(av)
-            rhwaddress = self.ipcmd.link_get_hwaddress(macvlan_ifacename)
-            raddress = self.ipcmd.addr_get(macvlan_ifacename)
-            if not raddress:
-                self.logger.warn('%s: no running addresses'
-                                 %ifaceobjrunning.name)
-                raddress = []
-            ifaceobjrunning.update_config('address-virtual',
-                            '%s %s' %(rhwaddress, ''.join(raddress)))
-        return
-
-    _run_ops = {'up' : _up,
-               'down' : _down,
-               'query-checkcurr' : _query_check,
-               'query-running' : _query_running}
-
-    def get_ops(self):
-        """ returns list of ops supported by this module """
-        return self._run_ops.keys()
-
-    def _init_command_handlers(self):
-        if not self.ipcmd:
-            self.ipcmd = iproute2(**self.get_flags())
-
-    def run(self, ifaceobj, operation, query_ifaceobj=None, **extra_args):
-        """ run vlan configuration on the interface object passed as argument
-
-        Args:
-            **ifaceobj** (object): iface object
-
-            **operation** (str): any of 'pre-up', 'post-down', 'query-checkcurr',
-                                 'query-running'
-        Kwargs:
-            **query_ifaceobj** (object): query check ifaceobject. This is only
-                valid when op is 'query-checkcurr'. It is an object same as
-                ifaceobj, but contains running attribute values and its config
-                status. The modules can use it to return queried running state
-                of interfaces. status is success if the running state is same
-                as user required state in ifaceobj. error otherwise.
-        """
-        if ifaceobj.type == ifaceType.BRIDGE_VLAN:
-            return
-        op_handler = self._run_ops.get(operation)
-        if not op_handler:
-            return
-        self._init_command_handlers()
-        if operation == 'query-checkcurr':
-            op_handler(self, ifaceobj, query_ifaceobj)
-        else:
-            op_handler(self, ifaceobj)
diff --git a/ifupdown2/addons/bridge.py b/ifupdown2/addons/bridge.py
deleted file mode 100644 (file)
index 012465a..0000000
+++ /dev/null
@@ -1,1575 +0,0 @@
-#!/usr/bin/python
-#
-# Copyright 2014 Cumulus Networks, Inc. All rights reserved.
-# Author: Roopa Prabhu, roopa@cumulusnetworks.com
-#
-
-from sets import Set
-from ifupdown.iface import *
-from ifupdownaddons.modulebase import moduleBase
-from ifupdownaddons.bridgeutils import brctl
-from ifupdownaddons.iproute2 import iproute2
-from collections import Counter
-import ifupdown.rtnetlink_api as rtnetlink_api
-import itertools
-import re
-import time
-
-class bridgeFlags:
-    PORT_PROCESSED = 0x1
-
-class bridge(moduleBase):
-    """  ifupdown2 addon module to configure linux bridges """
-
-    _modinfo = { 'mhelp' : 'Bridge configuration module. Supports both ' +
-                    'vlan aware and non vlan aware bridges. For the vlan ' +
-                    'aware bridge, the port specific attributes must be ' +
-                    'specified under the port. And for vlan unaware bridge ' +
-                    'port specific attributes must be specified under the ' +
-                    'bridge.',
-                 'attrs' : {
-                   'bridge-vlan-aware' :
-                        {'help' : 'vlan aware bridge. Setting this ' +
-                                  'attribute to yes enables vlan filtering' +
-                                  ' on the bridge',
-                         'example' : ['bridge-vlan-aware yes/no']},
-                   'bridge-ports' :
-                        {'help' : 'bridge ports',
-                         'required' : True,
-                         'example' : ['bridge-ports swp1.100 swp2.100 swp3.100',
-                                      'bridge-ports glob swp1-3.100',
-                                      'bridge-ports regex (swp[1|2|3].100)']},
-                   'bridge-stp' :
-                        {'help': 'bridge-stp yes/no',
-                         'example' : ['bridge-stp no'],
-                         'validvals' : ['yes', 'on', 'off', 'no'],
-                         'default' : 'no'},
-                   'bridge-bridgeprio' :
-                        {'help': 'bridge priority',
-                         'example' : ['bridge-bridgeprio 32768'],
-                         'default' : '32768'},
-                   'bridge-ageing' :
-                       {'help': 'bridge ageing',
-                         'example' : ['bridge-ageing 300'],
-                         'default' : '300'},
-                   'bridge-fd' :
-                        { 'help' : 'bridge forward delay',
-                          'example' : ['bridge-fd 15'],
-                          'default' : '15'},
-                   'bridge-gcint' :
-                        # XXX: recheck values
-                        { 'help' : 'bridge garbage collection interval in secs',
-                          'example' : ['bridge-gcint 4'],
-                          'default' : '4'},
-                   'bridge-hello' :
-                        { 'help' : 'bridge set hello time',
-                          'example' : ['bridge-hello 2'],
-                          'default' : '2'},
-                   'bridge-maxage' :
-                        { 'help' : 'bridge set maxage',
-                          'example' : ['bridge-maxage 20'],
-                          'default' : '20'},
-                   'bridge-pathcosts' :
-                        { 'help' : 'bridge set port path costs',
-                          'example' : ['bridge-pathcosts swp1=100 swp2=100'],
-                          'default' : '100'},
-                   'bridge-portprios' :
-                        { 'help' : 'bridge port prios',
-                          'example' : ['bridge-portprios swp1=32 swp2=32'],
-                          'default' : '32'},
-                   'bridge-mclmc' :
-                        { 'help' : 'set multicast last member count',
-                          'example' : ['bridge-mclmc 2'],
-                          'default' : '2'},
-                    'bridge-mcrouter' :
-                        { 'help' : 'set multicast router',
-                          'default' : '1',
-                          'example' : ['bridge-mcrouter 1']},
-                    'bridge-mcsnoop' :
-                        { 'help' : 'set multicast snooping',
-                          'default' : '1',
-                          'example' : ['bridge-mcsnoop 1']},
-                    'bridge-mcsqc' :
-                        { 'help' : 'set multicast startup query count',
-                          'default' : '2',
-                          'example' : ['bridge-mcsqc 2']},
-                    'bridge-mcqifaddr' :
-                        { 'help' : 'set multicast query to use ifaddr',
-                          'default' : '0',
-                          'example' : ['bridge-mcqifaddr 0']},
-                    'bridge-mcquerier' :
-                        { 'help' : 'set multicast querier',
-                          'default' : '0',
-                          'example' : ['bridge-mcquerier 0']},
-                    'bridge-hashel' :
-                        { 'help' : 'set hash elasticity',
-                          'default' : '4096',
-                          'example' : ['bridge-hashel 4096']},
-                    'bridge-hashmax' :
-                        { 'help' : 'set hash max',
-                          'default' : '4096',
-                          'example' : ['bridge-hashmax 4096']},
-                    'bridge-mclmi' :
-                        { 'help' : 'set multicast last member interval (in secs)',
-                          'default' : '1',
-                          'example' : ['bridge-mclmi 1']},
-                    'bridge-mcmi' :
-                        { 'help' : 'set multicast membership interval (in secs)',
-                          'default' : '260',
-                          'example' : ['bridge-mcmi 260']},
-                    'bridge-mcqpi' :
-                        { 'help' : 'set multicast querier interval (in secs)',
-                          'default' : '255',
-                          'example' : ['bridge-mcqpi 255']},
-                    'bridge-mcqi' :
-                        { 'help' : 'set multicast query interval (in secs)',
-                          'default' : '125',
-                          'example' : ['bridge-mcqi 125']},
-                    'bridge-mcqri' :
-                        { 'help' : 'set multicast query response interval (in secs)',
-                          'default' : '10',
-                          'example' : ['bridge-mcqri 10']},
-                    'bridge-mcsqi' :
-                        { 'help' : 'set multicast startup query interval (in secs)',
-                          'default' : '31',
-                          'example' : ['bridge-mcsqi 31']},
-                    'bridge-mcqv4src' :
-                        { 'help' : 'set per VLAN v4 multicast querier source address',
-                          'compat' : True,
-                          'example' : ['bridge-mcqv4src 100=172.16.100.1 101=172.16.101.1']},
-                    'bridge-portmcrouter' :
-                        { 'help' : 'set port multicast routers',
-                          'default' : '1',
-                          'example' : ['under the bridge: bridge-portmcrouter swp1=1 swp2=1',
-                                       'under the port: bridge-portmcrouter 1']},
-                    'bridge-portmcfl' :
-                        { 'help' : 'port multicast fast leave.',
-                          'default' : '0',
-                          'example' : ['under the bridge: bridge-portmcfl swp1=0 swp2=0',
-                                       'under the port: bridge-portmcfl 0']},
-                    'bridge-waitport' :
-                        { 'help' : 'wait for a max of time secs for the' +
-                                ' specified ports to become available,' +
-                                'if no ports are specified then those' +
-                                ' specified on bridge-ports will be' +
-                                ' used here. Specifying no ports here ' +
-                                'should not be used if we are using ' +
-                                'regex or \"all\" on bridge_ports,' +
-                                'as it wouldnt work.',
-                          'default' : '0',
-                          'example' : ['bridge-waitport 4 swp1 swp2']},
-                    'bridge-maxwait' :
-                        { 'help' : 'forces to time seconds the maximum time ' +
-                                'that the Debian bridge setup  scripts will ' +
-                                'wait for the bridge ports to get to the ' +
-                                'forwarding status, doesn\'t allow factional ' +
-                                'part. If it is equal to 0 then no waiting' +
-                                ' is done',
-                          'default' : '0',
-                          'example' : ['bridge-maxwait 3']},
-                    'bridge-vids' :
-                        { 'help' : 'bridge port vids. Can be specified ' +
-                                   'under the bridge or under the port. ' +
-                                   'If specified under the bridge the ports ' +
-                                   'inherit it unless overridden by a ' +
-                                   'bridge-vids attribuet under the port',
-                          'example' : ['bridge-vids 4000',
-                                       'bridge-vids 2000 2200-3000']},
-                    'bridge-pvid' :
-                        { 'help' : 'bridge port pvid. Must be specified under' +
-                                   ' the bridge port',
-                          'example' : ['bridge-pvid 1']},
-                    'bridge-access' :
-                        { 'help' : 'bridge port access vlan. Must be ' +
-                                   'specified under the bridge port',
-                          'example' : ['bridge-access 300']},
-                    'bridge-port-vids' :
-                        { 'help' : 'bridge vlans',
-                          'compat': True,
-                          'example' : ['bridge-port-vids bond0=1-1000,1010-1020']},
-                    'bridge-port-pvids' :
-                        { 'help' : 'bridge port vlans',
-                          'compat': True,
-                          'example' : ['bridge-port-pvids bond0=100 bond1=200']},
-                     }}
-
-    def __init__(self, *args, **kargs):
-        moduleBase.__init__(self, *args, **kargs)
-        self.ipcmd = None
-        self.name = self.__class__.__name__
-        self.brctlcmd = None
-        self._running_vidinfo = {}
-        self._running_vidinfo_valid = False
-        self._resv_vlan_range =  self._get_reserved_vlan_range()
-        self.logger.debug('%s: using reserved vlan range %s'
-                  %(self.__class__.__name__, str(self._resv_vlan_range)))
-
-    def _is_bridge(self, ifaceobj):
-        if ifaceobj.get_attr_value_first('bridge-ports'):
-            return True
-        return False
-
-    def _is_bridge_port(self, ifaceobj):
-        if self.brctlcmd.is_bridge_port(ifaceobj.name):
-            return True
-        return False
-
-    def get_dependent_ifacenames(self, ifaceobj, ifacenames_all=None):
-        if not self._is_bridge(ifaceobj):
-            return None
-        if ifaceobj.link_type != ifaceLinkType.LINK_NA:
-           ifaceobj.link_type = ifaceLinkType.LINK_MASTER
-        ifaceobj.link_kind |= ifaceLinkKind.BRIDGE
-        ifaceobj.role |= ifaceRole.MASTER
-        ifaceobj.dependency_type = ifaceDependencyType.MASTER_SLAVE
-        return self.parse_port_list(ifaceobj.get_attr_value_first(
-                                    'bridge-ports'), ifacenames_all)
-
-    def get_dependent_ifacenames_running(self, ifaceobj):
-        self._init_command_handlers()
-        if not self.brctlcmd.bridge_exists(ifaceobj.name):
-            return None
-        return self.brctlcmd.get_bridge_ports(ifaceobj.name)
-
-    def _get_bridge_port_list(self, ifaceobj):
-
-        # port list is also available in the previously
-        # parsed dependent list. Use that if available, instead
-        # of parsing port expr again
-        port_list = ifaceobj.lowerifaces
-        if port_list:
-            return port_list
-        ports = ifaceobj.get_attr_value_first('bridge-ports')
-        if ports:
-            return self.parse_port_list(ports)
-        else:
-            return None
-
-    def _process_bridge_waitport(self, ifaceobj, portlist):
-        waitport_value = ifaceobj.get_attr_value_first('bridge-waitport')
-        if not waitport_value: return
-        try:
-            waitportvals = re.split(r'[\s\t]\s*', waitport_value, 1)
-            if not waitportvals: return
-            try:
-                waitporttime = int(waitportvals[0])
-            except:
-                self.log_warn('%s: invalid waitport value \'%s\''
-                        %(ifaceobj.name, waitporttime))
-                return
-            if waitporttime <= 0: return
-            try:
-                waitportlist = self.parse_port_list(waitportvals[1])
-            except IndexError, e:
-                # ignore error and use all bridge ports
-                waitportlist = portlist
-                pass
-            if not waitportlist: return
-            self.logger.info('%s: waiting for ports %s to exist ...'
-                    %(ifaceobj.name, str(waitportlist)))
-            starttime = time.time()
-            while ((time.time() - starttime) < waitporttime):
-                if all([False for p in waitportlist
-                        if not self.ipcmd.link_exists(p)]):
-                    break;
-                time.sleep(1)
-        except Exception, e:
-            self.log_warn('%s: unable to process waitport: %s'
-                    %(ifaceobj.name, str(e)))
-
-    def _ports_enable_disable_ipv6(self, ports, enable='1'):
-        for p in ports:
-            try:
-                self.write_file('/proc/sys/net/ipv6/conf/%s' %p +
-                                '/disable_ipv6', enable)
-            except Exception, e:
-                self.logger.info(str(e))
-                pass
-
-    def _add_ports(self, ifaceobj):
-        bridgeports = self._get_bridge_port_list(ifaceobj)
-        runningbridgeports = []
-        removedbridgeports = []
-
-        self.ipcmd.batch_start()
-        self._process_bridge_waitport(ifaceobj, bridgeports)
-        self.ipcmd.batch_start()
-        # Delete active ports not in the new port list
-        if not self.PERFMODE:
-            runningbridgeports = self.brctlcmd.get_bridge_ports(ifaceobj.name)
-            if runningbridgeports:
-                for bport in runningbridgeports:
-                    if not bridgeports or bport not in bridgeports:
-                        self.ipcmd.link_set(bport, 'nomaster')
-                        removedbridgeports.append(bport)
-            else:
-                runningbridgeports = []
-        if not bridgeports:
-            self.ipcmd.batch_commit()
-            return
-        err = 0
-        for bridgeport in Set(bridgeports).difference(Set(runningbridgeports)):
-            try:
-                if not self.DRYRUN and not self.ipcmd.link_exists(bridgeport):
-                    self.log_warn('%s: bridge port %s does not exist'
-                                   %(ifaceobj.name, bridgeport))
-                    err += 1
-                    continue
-                hwaddress = self.ipcmd.link_get_hwaddress(bridgeport)
-                if not self._valid_ethaddr(hwaddress):
-                    self.log_warn('%s: skipping port %s, ' %(ifaceobj.name,
-                                  bridgeport) + 'invalid ether addr %s'
-                                  %hwaddress)
-                    continue
-                self.ipcmd.link_set(bridgeport, 'master', ifaceobj.name)
-                self.ipcmd.addr_flush(bridgeport)
-            except Exception, e:
-                self.logger.error(str(e))
-                pass
-        try:
-            self.ipcmd.batch_commit()
-        except Exception, e:
-            self.logger.error(str(e))
-            pass
-
-        # enable ipv6 for ports that were removed
-        self._ports_enable_disable_ipv6(removedbridgeports, '0')
-        if err:
-            self.log_error('bridge configuration failed (missing ports)')
-
-
-    def _process_bridge_maxwait(self, ifaceobj, portlist):
-        maxwait = ifaceobj.get_attr_value_first('bridge-maxwait')
-        if not maxwait: return
-        try:
-            maxwait = int(maxwait)
-        except:
-            self.log_warn('%s: invalid maxwait value \'%s\'' %(ifaceobj.name,
-                    maxwait))
-            return
-        if not maxwait: return
-        self.logger.info('%s: waiting for ports to go to fowarding state ..'
-                %ifaceobj.name)
-        try:
-            starttime = time.time()
-            while ((time.time() - starttime) < maxwait):
-                if all([False for p in portlist
-                    if self.read_file_oneline(
-                            '/sys/class/net/%s/brif/%s/state'
-                            %(ifaceobj.name, p)) != '3']):
-                    break;
-                time.sleep(1)
-        except Exception, e:
-            self.log_warn('%s: unable to process maxwait: %s'
-                    %(ifaceobj.name, str(e)))
-
-    def _ints_to_ranges(self, ints):
-        for a, b in itertools.groupby(enumerate(ints), lambda (x, y): y - x):
-            b = list(b)
-            yield b[0][1], b[-1][1]
-
-    def _ranges_to_ints(self, rangelist):
-        """ returns expanded list of integers given set of string ranges
-        example: ['1', '2-4', '6'] returns [1, 2, 3, 4, 6]
-        """
-        result = []
-        for part in rangelist:
-            if '-' in part:
-                a, b = part.split('-')
-                a, b = int(a), int(b)
-                result.extend(range(a, b + 1))
-            else:
-                a = int(part)
-                result.append(a)
-        return result
-
-    def _diff_vids(self, vids1, vids2):
-        vids_to_add = None
-        vids_to_del = None
-
-        vids1_ints = self._ranges_to_ints(vids1)
-        vids2_ints = self._ranges_to_ints(vids2)
-        vids1_diff = Set(vids1_ints).difference(vids2_ints)
-        vids2_diff = Set(vids2_ints).difference(vids1_ints)
-        if vids1_diff:
-            vids_to_add = ['%d' %start if start == end else '%d-%d' %(start, end)
-                        for start, end in self._ints_to_ranges(vids1_diff)]
-        if vids2_diff:
-            vids_to_del = ['%d' %start if start == end else '%d-%d' %(start, end)
-                        for start, end in self._ints_to_ranges(vids2_diff)]
-        return (vids_to_del, vids_to_add)
-
-    def _compare_vids(self, vids1, vids2):
-        """ Returns true if the vids are same else return false """
-
-        vids1_ints = self._ranges_to_ints(vids1)
-        vids2_ints = self._ranges_to_ints(vids2)
-        if Set(vids1_ints).symmetric_difference(vids2_ints):
-            return False
-        else:
-            return True
-
-    def _set_bridge_mcqv4src_compat(self, ifaceobj):
-        #
-        # Sets old style igmp querier
-        #
-        attrval = ifaceobj.get_attr_value_first('bridge-mcqv4src')
-        if attrval:
-            running_mcqv4src = {}
-            if not self.PERFMODE:
-                running_mcqv4src = self.brctlcmd.get_mcqv4src(ifaceobj.name)
-            mcqs = {}
-            srclist = attrval.split()
-            for s in srclist:
-                k, v = s.split('=')
-                mcqs[k] = v
-
-            k_to_del = Set(running_mcqv4src.keys()).difference(mcqs.keys())
-            for v in k_to_del:
-                self.brctlcmd.del_mcqv4src(ifaceobj.name, v)
-            for v in mcqs.keys():
-                self.brctlcmd.set_mcqv4src(ifaceobj.name, v, mcqs[v])
-
-    def _get_running_vidinfo(self):
-        if self._running_vidinfo_valid:
-            return self._running_vidinfo
-        self._running_vidinfo = {}
-        if not self.PERFMODE:
-            self._running_vidinfo = self.ipcmd.bridge_port_vids_get_all()
-        self._running_vidinfo_valid = True
-        return self._running_vidinfo
-
-    def _flush_running_vidinfo(self):
-        self._running_vidinfo = {}
-        self._running_vidinfo_valid = False
-
-    def _set_bridge_vidinfo_compat(self, ifaceobj):
-        #
-        # Supports old style vlan vid info format
-        # for compatibility
-        #
-
-        # Handle bridge vlan attrs
-        running_vidinfo = self._get_running_vidinfo()
-
-        # Install pvids
-        attrval = ifaceobj.get_attr_value_first('bridge-port-pvids')
-        if attrval:
-            portlist = self.parse_port_list(attrval)
-            if not portlist:
-                self.log_warn('%s: could not parse \'%s %s\''
-                              %(ifaceobj.name, attrname, attrval))
-                return
-            for p in portlist:
-                try:
-                    (port, pvid) = p.split('=')
-                    running_pvid = running_vidinfo.get(port, {}).get('pvid')
-                    if running_pvid:
-                        if running_pvid == pvid:
-                            continue
-                        else:
-                            self.ipcmd.bridge_port_pvid_del(port, running_pvid)
-                    self.ipcmd.bridge_port_pvid_add(port, pvid)
-                except Exception, e:
-                    self.log_warn('%s: failed to set pvid `%s` (%s)'
-                            %(ifaceobj.name, p, str(e)))
-
-        # install port vids
-        attrval = ifaceobj.get_attr_value_first('bridge-port-vids')
-        if attrval:
-            portlist = self.parse_port_list(attrval)
-            if not portlist:
-                self.log_warn('%s: could not parse \'%s %s\''
-                          %(ifaceobj.name, attrname, attrval))
-                return
-            for p in portlist:
-                try:
-                    (port, val) = p.split('=')
-                    vids = val.split(',')
-                    if running_vidinfo.get(port):
-                        (vids_to_del, vids_to_add) = \
-                                self._diff_vids(vids,
-                                running_vidinfo.get(port).get('vlan'))
-                        if vids_to_del:
-                            self.ipcmd.bridge_port_vids_del(port, vids_to_del)
-                        if vids_to_add:
-                            self.ipcmd.bridge_port_vids_add(port, vids_to_add)
-                    else:
-                        self.ipcmd.bridge_port_vids_add(port, vids)
-                except Exception, e:
-                    self.log_warn('%s: failed to set vid `%s` (%s)'
-                        %(ifaceobj.name, p, str(e)))
-
-        # install vids
-        # XXX: Commenting out this code for now because it was decided
-        # that this is not needed
-        #attrval = ifaceobj.get_attr_value_first('bridge-vids')
-        #if attrval:
-        #    vids = re.split(r'[\s\t]\s*', attrval)
-        #    if running_vidinfo.get(ifaceobj.name):
-        #        (vids_to_del, vids_to_add) = \
-        #                self._diff_vids(vids,
-        #                    running_vidinfo.get(ifaceobj.name).get('vlan'))
-        #        if vids_to_del:
-        #            self.ipcmd.bridge_vids_del(ifaceobj.name, vids_to_del)
-        #        if vids_to_add:
-        #            self.ipcmd.bridge_vids_add(ifaceobj.name, vids_to_add)
-        #    else:
-        #        self.ipcmd.bridge_vids_add(ifaceobj.name, vids)
-        #else:
-        #    running_vids = running_vidinfo.get(ifaceobj.name)
-        #    if running_vids:
-        #        self.ipcmd.bridge_vids_del(ifaceobj.name, running_vids)
-
-    def _apply_bridge_settings(self, ifaceobj):
-        try:
-            stp = ifaceobj.get_attr_value_first('bridge-stp')
-            if stp:
-                self.brctlcmd.set_stp(ifaceobj.name, stp)
-            else:
-                # If stp not specified and running stp state on, set it to off
-                running_stp_state = self.read_file_oneline(
-                       '/sys/class/net/%s/bridge/stp_state' %ifaceobj.name)
-                if running_stp_state and running_stp_state != '0':
-                   self.brctlcmd.set_stp(ifaceobj.name, 'no')
-
-            if ifaceobj.get_attr_value_first('bridge-vlan-aware') == 'yes':
-               self.write_file('/sys/class/net/%s/bridge/vlan_filtering'
-                       %ifaceobj.name, '1')
-            # Use the brctlcmd bulk set method: first build a dictionary
-            # and then call set
-            bridgeattrs = { k:v for k,v in
-                             {'ageing' :
-                                ifaceobj.get_attr_value_first('bridge-ageing'),
-                              'bridgeprio' :
-                                ifaceobj.get_attr_value_first(
-                                                        'bridge-bridgeprio'),
-                              'fd' :
-                                ifaceobj.get_attr_value_first('bridge-fd'),
-                              'gcint' :
-                                ifaceobj.get_attr_value_first('bridge-gcint'),
-                              'hello' :
-                                ifaceobj.get_attr_value_first('bridge-hello'),
-                              'maxage' :
-                                ifaceobj.get_attr_value_first('bridge-maxage'),
-                              'mclmc' :
-                                ifaceobj.get_attr_value_first('bridge-mclmc'),
-                              'mcrouter' :
-                                ifaceobj.get_attr_value_first(
-                                                            'bridge-mcrouter'),
-                              'mcsnoop' :
-                                ifaceobj.get_attr_value_first('bridge-mcsnoop'),
-                              'mcsqc' :
-                                ifaceobj.get_attr_value_first('bridge-mcsqc'),
-                              'mcqifaddr' :
-                                ifaceobj.get_attr_value_first(
-                                                            'bridge-mcqifaddr'),
-                              'mcquerier' :
-                                ifaceobj.get_attr_value_first(
-                                                            'bridge-mcquerier'),
-                              'hashel' :
-                                ifaceobj.get_attr_value_first('bridge-hashel'),
-                              'hashmax' :
-                                ifaceobj.get_attr_value_first('bridge-hashmax'),
-                              'mclmi' :
-                                ifaceobj.get_attr_value_first('bridge-mclmi'),
-                              'mcmi' :
-                                ifaceobj.get_attr_value_first('bridge-mcmi'),
-                              'mcqpi' :
-                                ifaceobj.get_attr_value_first('bridge-mcqpi'),
-                              'mcqi' :
-                                ifaceobj.get_attr_value_first('bridge-mcqi'),
-                              'mcqri' :
-                                ifaceobj.get_attr_value_first('bridge-mcqri'),
-                              'mcsqi' :
-                                ifaceobj.get_attr_value_first('bridge-mcsqi')
-                               }.items()
-                            if v }
-            if bridgeattrs:
-                self.brctlcmd.set_bridge_attrs(ifaceobj.name, bridgeattrs)
-            portattrs = {}
-            for attrname, dstattrname in {'bridge-pathcosts' : 'pathcost',
-                                'bridge-portprios' : 'portprio',
-                                'bridge-portmcrouter' : 'portmcrouter',
-                                'bridge-portmcfl' : 'portmcfl'}.items():
-                attrval = ifaceobj.get_attr_value_first(attrname)
-                if not attrval:
-                    continue
-                portlist = self.parse_port_list(attrval)
-                if not portlist:
-                    self.log_warn('%s: could not parse \'%s %s\''
-                         %(ifaceobj.name, attrname, attrval))
-                    continue
-                for p in portlist:
-                    try:
-                        (port, val) = p.split('=')
-                        if not portattrs.get(port):
-                            portattrs[port] = {}
-                        portattrs[port].update({dstattrname : val})
-                    except Exception, e:
-                        self.log_warn('%s: could not parse %s (%s)'
-                                    %(ifaceobj.name, attrname, str(e)))
-            for port, attrdict in portattrs.iteritems():
-                try:
-                    self.brctlcmd.set_bridgeport_attrs(ifaceobj.name, port,
-                                                       attrdict)
-                except Exception, e:
-                    self.log_warn('%s: %s', str(e))
-                    pass
-            self._set_bridge_vidinfo_compat(ifaceobj)
-            self._set_bridge_mcqv4src_compat(ifaceobj)
-            self._process_bridge_maxwait(ifaceobj,
-                    self._get_bridge_port_list(ifaceobj))
-        except Exception, e:
-            self.log_warn(str(e))
-
-    def _check_vids(self, ifaceobj, vids):
-        ret = True
-        for v in vids:
-            if '-' in v:
-                va, vb = v.split('-')
-                va, vb = int(va), int(vb)
-                if (self._handle_reserved_vlan(va, ifaceobj.name) or
-                    self._handle_reserved_vlan(vb, ifaceobj.name)):
-                    ret = False
-            else:
-                va = int(v)
-                if self._handle_reserved_vlan(va, ifaceobj.name):
-                   ret = False
-        return ret
-         
-    def _apply_bridge_vids(self, bportifaceobj, vids, running_vids, isbridge):
-        try:
-            if not self._check_vids(bportifaceobj, vids):
-               return
-            if running_vids:
-                (vids_to_del, vids_to_add) = \
-                    self._diff_vids(vids, running_vids)
-                if vids_to_del:
-                    self.ipcmd.bridge_vids_del(bportifaceobj.name,
-                                               vids_to_del, isbridge)
-                if vids_to_add:
-                    self.ipcmd.bridge_vids_add(bportifaceobj.name,
-                                               vids_to_add, isbridge)
-            else:
-                self.ipcmd.bridge_vids_add(bportifaceobj.name, vids, isbridge)
-        except Exception, e:
-                self.log_warn('%s: failed to set vid `%s` (%s)'
-                        %(bportifaceobj.name, str(vids), str(e)))
-
-    def _apply_bridge_port_pvids(self, bportifaceobj, pvid, running_pvid):
-        # Install pvids
-        try:
-            if running_pvid:
-                if running_pvid != pvid:
-                    self.ipcmd.bridge_port_pvid_del(bportifaceobj.name,
-                                                    running_pvid)
-                self.ipcmd.bridge_port_pvid_add(bportifaceobj.name, pvid)
-            else:
-                self.ipcmd.bridge_port_pvid_add(bportifaceobj.name, pvid)
-        except Exception, e:
-            self.log_warn('%s: failed to set pvid `%s` (%s)'
-                          %(bportifaceobj.name, pvid, str(e)))
-
-    def _apply_bridge_vids_and_pvid(self, bportifaceobj, vids, running_vids,
-                                    pvid, running_pvid, isbridge):
-        """ This method is a combination of methods _apply_bridge_vids and
-            _apply_bridge_port_pvids above. A combined function is
-            found necessary to do the deletes first and the adds later
-            because kernel does honor vid info flags during deletes.
-
-        """
-
-        try:
-            if not self._check_vids(bportifaceobj, vids):
-               return
-
-            vids_to_del = []
-            vids_to_add = vids
-            pvid_to_del = None
-            pvid_to_add = pvid if pvid else '1'
-
-            if running_vids:
-                (vids_to_del, vids_to_add) = \
-                    self._diff_vids(vids, running_vids)
-
-            if running_pvid:
-                if running_pvid != pvid:
-                    pvid_to_del = running_pvid
-
-            if (pvid_to_del and (pvid_to_del in vids) and
-                (pvid_to_del not in vids_to_add)):
-                # kernel deletes dont take into account
-                # bridge vid flags and its possible that
-                # the pvid deletes we do end up deleting
-                # the vids. Be proactive and add the pvid
-                # to the vid add list if it is in the vids
-                # and not already part of vids_to_add.
-                # This helps with a small corner case:
-                #   - running
-                #       pvid 100
-                #       vid 101 102
-                #   - new change is going to move the state to
-                #       pvid 101
-                #       vid 100 102
-                vids_to_add.append(pvid_to_del)
-        except Exception, e:
-            self.log_warn('%s: failed to process vids/pvids'
-                          %bportifaceobj.name + ' vids = %s' %str(vids) +
-                          'pvid = %s ' %pvid + '(%s)' %str(e))
-        try:
-            if vids_to_del:
-               self.ipcmd.bridge_vids_del(bportifaceobj.name,
-                                          vids_to_del, isbridge)
-        except Exception, e:
-                self.log_warn('%s: failed to del vid `%s` (%s)'
-                        %(bportifaceobj.name, str(vids_to_del), str(e)))
-
-        try:
-            if pvid_to_del:
-               self.ipcmd.bridge_port_pvid_del(bportifaceobj.name,
-                                               pvid_to_del)
-        except Exception, e:
-                self.log_warn('%s: failed to del pvid `%s` (%s)'
-                        %(bportifaceobj.name, pvid_to_del, str(e)))
-
-        try:
-            if vids_to_add:
-               self.ipcmd.bridge_vids_add(bportifaceobj.name,
-                                           vids_to_add, isbridge)
-        except Exception, e:
-                self.log_warn('%s: failed to set vid `%s` (%s)'
-                        %(bportifaceobj.name, str(vids_to_add), str(e)))
-
-        try:
-            self.ipcmd.bridge_port_pvid_add(bportifaceobj.name, pvid_to_add)
-        except Exception, e:
-                self.log_warn('%s: failed to set pvid `%s` (%s)'
-                        %(bportifaceobj.name, pvid_to_add, str(e)))
-
-    def _apply_bridge_vlan_aware_port_settings_all(self, bportifaceobj,
-                                                   bridge_vids=None,
-                                                   bridge_pvid=None):
-        running_vidinfo = self._get_running_vidinfo()
-        vids = None
-        pvids = None
-        vids_final = []
-        pvid_final = None
-        bport_access = bportifaceobj.get_attr_value_first('bridge-access')
-        if bport_access:
-            vids = re.split(r'[\s\t]\s*', bport_access)
-            pvids = vids
-        else:
-            bport_vids = bportifaceobj.get_attr_value_first('bridge-vids')
-            if bport_vids:
-                vids = re.split(r'[\s\t,]\s*', bport_vids)
-
-            bport_pvids = bportifaceobj.get_attr_value_first('bridge-pvid')
-            if bport_pvids:
-                pvids = re.split(r'[\s\t]\s*', bport_pvids)
-
-        if vids:
-            vids_final =  vids
-        elif bridge_vids:
-            vids_final = bridge_vids
-
-        if pvids:
-            pvid_final = pvids[0]
-        elif bridge_pvid:
-            pvid_final = bridge_pvid
-
-        self._apply_bridge_vids_and_pvid(bportifaceobj, vids_final,
-                running_vidinfo.get(bportifaceobj.name, {}).get('vlan'),
-                pvid_final,
-                running_vidinfo.get(bportifaceobj.name, {}).get('pvid'),
-                False)
-
-    def _apply_bridge_port_settings(self, bportifaceobj, bridgename=None,
-                                    bridgeifaceobj=None):
-        if not bridgename and bridgeifaceobj:
-            bridgename = bridgeifaceobj.name
-        # Set other stp and igmp attributes
-        portattrs = {}
-        for attrname, dstattrname in {
-            'bridge-pathcosts' : 'pathcost',
-            'bridge-portprios' : 'portprio',
-            'bridge-portmcrouter' : 'portmcrouter',
-            'bridge-portmcfl' : 'portmcfl'}.items():
-            attrval = bportifaceobj.get_attr_value_first(attrname)
-            if not attrval:
-                # Check if bridge has that attribute
-                #if bridgeifaceobj:
-                #    attrval = bridgeifaceobj.get_attr_value_first(attrname)
-                #    if not attrval:
-                #        continue
-                #else:
-                continue
-            portattrs[dstattrname] = attrval
-        try:
-            self.brctlcmd.set_bridgeport_attrs(bridgename,
-                            bportifaceobj.name, portattrs)
-        except Exception, e:
-            self.log_warn(str(e))
-
-    def _apply_bridge_port_settings_all(self, ifaceobj,
-                                        ifaceobj_getfunc=None):
-        err = False
-        bridge_vlan_aware = ifaceobj.get_attr_value_first(
-                                           'bridge-vlan-aware')
-        if bridge_vlan_aware and bridge_vlan_aware == 'yes':
-           bridge_vlan_aware = True
-        else:
-           bridge_vlan_aware = False
-
-        if (ifaceobj.get_attr_value_first('bridge-port-vids') and
-                ifaceobj.get_attr_value_first('bridge-port-pvids')):
-            # Old style bridge port vid info
-            # skip new style setting on ports
-            return
-        self.logger.info('%s: applying bridge configuration '
-                         %ifaceobj.name + 'specific to ports')
-
-        bridge_vids = ifaceobj.get_attr_value_first('bridge-vids')
-        if bridge_vids:
-           bridge_vids = re.split(r'[\s\t,]\s*', bridge_vids)
-        else:
-           bridge_vids = None
-
-        bridge_pvid = ifaceobj.get_attr_value_first('bridge-pvid')
-        if bridge_pvid:
-           bridge_pvid = re.split(r'[\s\t]\s*', bridge_pvid)[0]
-        else:
-           bridge_pvid = None
-
-        bridgeports = self._get_bridge_port_list(ifaceobj)
-        if not bridgeports:
-           self.logger.debug('%s: cannot find bridgeports' %ifaceobj.name)
-           return
-        for bport in bridgeports:
-            # Use the brctlcmd bulk set method: first build a dictionary
-            # and then call set
-            if not self.ipcmd.bridge_port_exists(ifaceobj.name, bport):
-                self.logger.info('%s: skipping bridge config' %ifaceobj.name +
-                        ' for port %s (missing port)' %bport)
-                continue
-            self.logger.info('%s: processing bridge config for port %s'
-                             %(ifaceobj.name, bport))
-            bportifaceobjlist = ifaceobj_getfunc(bport)
-            if not bportifaceobjlist:
-               continue
-            for bportifaceobj in bportifaceobjlist:
-                # Dont process bridge port if it already has been processed
-                if (bportifaceobj.module_flags.get(self.name,0x0) & \
-                    bridgeFlags.PORT_PROCESSED):
-                    continue
-                try:
-                    # Add attributes specific to the vlan aware bridge
-                    if bridge_vlan_aware:
-                        self._apply_bridge_vlan_aware_port_settings_all(
-                                bportifaceobj, bridge_vids, bridge_pvid)
-                        self._apply_bridge_port_settings(bportifaceobj,
-                                                 bridgeifaceobj=ifaceobj)
-                except Exception, e:
-                    err = True
-                    self.logger.warn('%s: %s' %(ifaceobj.name, str(e)))
-                    pass
-        if err:
-           raise Exception('%s: errors applying port settings' %ifaceobj.name)
-
-    def _up(self, ifaceobj, ifaceobj_getfunc=None):
-        # Check if bridge port
-        bridgename = self.ipcmd.bridge_port_get_bridge_name(ifaceobj.name)
-        if bridgename:
-           if self.ipcmd.bridge_is_vlan_aware(bridgename):
-              bridge_vids = self._get_bridge_vids(bridgename,
-                                                  ifaceobj_getfunc)
-              bridge_pvid = self._get_bridge_pvid(bridgename,
-                                                   ifaceobj_getfunc)
-              self._apply_bridge_vlan_aware_port_settings_all(ifaceobj,
-                                                              bridge_vids,
-                                                              bridge_pvid)
-           self._apply_bridge_port_settings(ifaceobj, bridgename=bridgename)
-           ifaceobj.module_flags[self.name] = ifaceobj.module_flags.setdefault(self.name,0) | \
-                                              bridgeFlags.PORT_PROCESSED
-           return
-        if not self._is_bridge(ifaceobj):
-            return
-        err = False
-        errstr = ''
-        running_ports = ''
-        try:
-            if not self.PERFMODE:
-                if not self.ipcmd.link_exists(ifaceobj.name):
-                   self.ipcmd.link_create(ifaceobj.name, 'bridge')
-            else:
-                self.ipcmd.link_create(ifaceobj.name, 'bridge')
-        except Exception, e:
-            raise Exception(str(e))
-        try:
-            self._add_ports(ifaceobj)
-        except Exception, e:
-            err = True
-            errstr = str(e)
-            pass
-
-        try:
-            self._apply_bridge_settings(ifaceobj)
-        except Exception, e:
-            err = True
-            errstr = str(e)
-            pass
-
-        try:
-            running_ports = self.brctlcmd.get_bridge_ports(ifaceobj.name)
-            if not running_ports:
-               return
-            # disable ipv6 for ports that were added to bridge
-            self._ports_enable_disable_ipv6(running_ports, '1')
-            self._apply_bridge_port_settings_all(ifaceobj,
-                            ifaceobj_getfunc=ifaceobj_getfunc)
-        except Exception, e:
-            err = True
-            errstr = str(e)
-            pass
-            #self._flush_running_vidinfo()
-        finally:
-            if ifaceobj.link_type != ifaceLinkType.LINK_NA:
-                for p in running_ports:
-                    try:
-                        rtnetlink_api.rtnl_api.link_set(p, "up")
-                    except Exception, e:
-                        self.logger.debug('%s: %s: link set up (%s)'
-                                          %(ifaceobj.name, p, str(e)))
-                        pass
-
-            if ifaceobj.addr_method == 'manual':
-               rtnetlink_api.rtnl_api.link_set(ifaceobj.name, "up")
-        if err:
-            raise Exception(errstr)
-
-    def _down(self, ifaceobj, ifaceobj_getfunc=None):
-        try:
-            if ifaceobj.get_attr_value_first('bridge-ports'):
-                ports = self.brctlcmd.get_bridge_ports(ifaceobj.name)
-                self.brctlcmd.delete_bridge(ifaceobj.name)
-                if ports:
-                    self._ports_enable_disable_ipv6(ports, '0')
-                    if ifaceobj.link_type != ifaceLinkType.LINK_NA:
-                        map(lambda p: rtnetlink_api.rtnl_api.link_set(p,
-                                    "down"), ports)
-        except Exception, e:
-            self.log_error(str(e))
-
-    def _query_running_vidinfo_compat(self, ifaceobjrunning, ports):
-        running_attrs = {}
-        running_vidinfo = self._get_running_vidinfo()
-        if ports:
-            running_bridge_port_vids = ''
-            for p in ports:
-                try:
-                    running_vids = running_vidinfo.get(p, {}).get('vlan')
-                    if running_vids:
-                        running_bridge_port_vids += ' %s=%s' %(p,
-                                                      ','.join(running_vids))
-                except Exception:
-                    pass
-            running_attrs['bridge-port-vids'] = running_bridge_port_vids
-
-            running_bridge_port_pvids = ''
-            for p in ports:
-                try:
-                    running_pvids = running_vidinfo.get(p, {}).get('pvid')
-                    if running_pvids:
-                        running_bridge_port_pvids += ' %s=%s' %(p,
-                                                        running_pvids)
-                except Exception:
-                    pass
-            running_attrs['bridge-port-pvids'] = running_bridge_port_pvids
-
-        running_bridge_vids = running_vidinfo.get(ifaceobjrunning.name,
-                                                  {}).get('vlan')
-        if running_bridge_vids:
-            running_attrs['bridge-vids'] = ','.join(running_bridge_vids)
-        return running_attrs
-
-    def _query_running_vidinfo(self, ifaceobjrunning, ifaceobj_getfunc,
-                               bridgeports=None):
-        running_attrs = {}
-        running_vidinfo = self._get_running_vidinfo()
-        if not running_vidinfo:
-           return running_attrs
-
-        # 'bridge-vids' under the bridge is all about 'vids' on the port.
-        # so query the ports
-        running_bridgeport_vids = []
-        running_bridgeport_pvids = []
-        for bport in bridgeports:
-            vids = running_vidinfo.get(bport, {}).get('vlan')
-            if vids:
-                running_bridgeport_vids.append(' '.join(vids))
-            pvids = running_vidinfo.get(bport, {}).get('pvid')
-            if pvids:
-                running_bridgeport_pvids.append(pvids[0])
-
-        bridge_vids = None
-        if running_bridgeport_vids: 
-           (vidval, freq) = Counter(running_bridgeport_vids).most_common()[0]
-           if freq == len(bridgeports):
-              running_attrs['bridge-vids'] = vidval
-              bridge_vids = vidval.split()
-
-        bridge_pvid = None
-        if running_bridgeport_pvids:
-           (vidval, freq) = Counter(running_bridgeport_pvids).most_common()[0]
-           if freq == len(bridgeports) and vidval != '1':
-              running_attrs['bridge-pvid'] = vidval
-              bridge_pvid = vidval.split()
-
-        # Go through all bridge ports and find their vids
-        for bport in bridgeports:
-            bportifaceobj = ifaceobj_getfunc(bport)
-            if not bportifaceobj:
-               continue
-            bport_vids = None
-            bport_pvids = None
-            vids = running_vidinfo.get(bport, {}).get('vlan')
-            if vids and vids != bridge_vids:
-               bport_vids = vids
-            pvids = running_vidinfo.get(bport, {}).get('pvid')
-            if pvids and pvids[0] != bridge_pvid:
-               bport_pvids = pvids
-            if not bport_vids and bport_pvids and bport_pvids[0] != '1':
-               bportifaceobj[0].replace_config('bridge-access', bport_pvids[0])
-            else:
-               if bport_pvids and bport_pvids[0] != '1':
-                  bportifaceobj[0].replace_config('bridge-pvid', bport_pvids[0])
-               else:
-                  # delete any stale bridge-vids under ports
-                  bportifaceobj[0].delete_config('bridge-pvid')
-               if bport_vids:
-                  bportifaceobj[0].replace_config('bridge-vids',
-                                                  ' '.join(bport_vids))
-               else:
-                  # delete any stale bridge-vids under ports
-                  bportifaceobj[0].delete_config('bridge-vids')
-        return running_attrs
-
-    def _query_running_mcqv4src(self, ifaceobjrunning):
-        running_mcqv4src = self.brctlcmd.get_mcqv4src(ifaceobjrunning.name)
-        mcqs = ['%s=%s' %(v, i) for v, i in running_mcqv4src.items()]
-        mcqs.sort()
-        mcq = ' '.join(mcqs)
-        return mcq
-
-    def _query_running_attrs(self, ifaceobjrunning, ifaceobj_getfunc,
-                             bridge_vlan_aware=False):
-        bridgeattrdict = {}
-        userspace_stp = 0
-        ports = None
-        skip_kernel_stp_attrs = 0
-
-        if self.sysctl_get('net.bridge.bridge-stp-user-space') == '1':
-            userspace_stp = 1
-
-        tmpbridgeattrdict = self.brctlcmd.get_bridge_attrs(ifaceobjrunning.name)
-        if not tmpbridgeattrdict:
-            self.logger.warn('%s: unable to get bridge attrs'
-                    %ifaceobjrunning.name)
-            return bridgeattrdict
-
-        # Fill bridge_ports and bridge stp attributes first
-        ports = tmpbridgeattrdict.get('ports')
-        if ports:
-            bridgeattrdict['bridge-ports'] = [' '.join(ports.keys())]
-        stp = tmpbridgeattrdict.get('stp', 'no')
-        if stp != self.get_mod_subattr('bridge-stp', 'default'):
-            bridgeattrdict['bridge-stp'] = [stp]
-
-        if  stp == 'yes' and userspace_stp:
-            skip_kernel_stp_attrs = 1
-
-        # pick all other attributes
-        for k,v in tmpbridgeattrdict.items():
-            if not v:
-                continue
-            if k == 'ports' or k == 'stp':
-                continue
-
-            if skip_kernel_stp_attrs and k[:2] != 'mc':
-                # only include igmp attributes if kernel stp is off
-                continue
-            attrname = 'bridge-' + k
-            if v != self.get_mod_subattr(attrname, 'default'):
-                bridgeattrdict[attrname] = [v]
-
-        if bridge_vlan_aware:
-            bridgevidinfo = self._query_running_vidinfo(ifaceobjrunning,
-                                                        ifaceobj_getfunc,
-                                                        ports.keys())
-        else:
-            bridgevidinfo = self._query_running_vidinfo_compat(ifaceobjrunning,
-                                                               ports)
-        if bridgevidinfo:
-           bridgeattrdict.update({k : [v] for k, v in bridgevidinfo.items()
-                                  if v})
-
-        mcq = self._query_running_mcqv4src(ifaceobjrunning)
-        if mcq:
-            bridgeattrdict['bridge-mcqv4src'] = [mcq]
-
-        if skip_kernel_stp_attrs:
-            return bridgeattrdict
-
-        if ports:
-            portconfig = {'bridge-pathcosts' : '',
-                          'bridge-portprios' : ''}
-            for p, v in ports.items():
-                v = self.brctlcmd.get_pathcost(ifaceobjrunning.name, p)
-                if v and v != self.get_mod_subattr('bridge-pathcosts',
-                                                   'default'):
-                    portconfig['bridge-pathcosts'] += ' %s=%s' %(p, v)
-
-                v = self.brctlcmd.get_portprio(ifaceobjrunning.name, p)
-                if v and v != self.get_mod_subattr('bridge-portprios',
-                                                   'default'):
-                    portconfig['bridge-portprios'] += ' %s=%s' %(p, v)
-
-            bridgeattrdict.update({k : [v] for k, v in portconfig.items()
-                                    if v})
-
-        return bridgeattrdict
-
-    def _query_check_mcqv4src(self, ifaceobj, ifaceobjcurr):
-        running_mcqs = self._query_running_mcqv4src(ifaceobj)
-        attrval = ifaceobj.get_attr_value_first('bridge-mcqv4src')
-        if attrval:
-            mcqs = attrval.split()
-            mcqs.sort()
-            mcqsout = ' '.join(mcqs)
-            ifaceobjcurr.update_config_with_status('bridge-mcqv4src',
-                         running_mcqs, 1 if running_mcqs != mcqsout else 0)
-
-    def _query_check_bridge_vidinfo(self, ifaceobj, ifaceobjcurr):
-        err = 0
-        running_vidinfo = self._get_running_vidinfo()
-        attrval = ifaceobj.get_attr_value_first('bridge-port-vids')
-        if attrval:
-            running_bridge_port_vids = ''
-            portlist = self.parse_port_list(attrval)
-            if not portlist:
-                self.log_warn('%s: could not parse \'%s %s\''
-                          %(ifaceobj.name, attrname, attrval))
-                return
-            err = 0
-            for p in portlist:
-                try:
-                    (port, val) = p.split('=')
-                    vids = val.split(',')
-                    running_vids = running_vidinfo.get(port, {}).get('vlan')
-                    if running_vids:
-                        if not self._compare_vids(vids, running_vids):
-                            err += 1
-                            running_bridge_port_vids += ' %s=%s' %(port,
-                                                      ','.join(running_vids))
-                        else:
-                            running_bridge_port_vids += ' %s' %p
-                    else:
-                        err += 1
-                except Exception, e:
-                    self.log_warn('%s: failure checking vid %s (%s)'
-                        %(ifaceobj.name, p, str(e)))
-            if err:
-                ifaceobjcurr.update_config_with_status('bridge-port-vids',
-                                                 running_bridge_port_vids, 1)
-            else:
-                ifaceobjcurr.update_config_with_status('bridge-port-vids',
-                                                 attrval, 0)
-
-        attrval = ifaceobj.get_attr_value_first('bridge-port-pvids')
-        if attrval:
-            portlist = self.parse_port_list(attrval)
-            if not portlist:
-                self.log_warn('%s: could not parse \'%s %s\''
-                              %(ifaceobj.name, attrname, attrval))
-                return
-            running_bridge_port_pvids = ''
-            err = 0
-            for p in portlist:
-                try:
-                    (port, pvid) = p.split('=')
-                    running_pvid = running_vidinfo.get(port, {}).get('pvid')
-                    if running_pvid and running_pvid == pvid:
-                        running_bridge_port_pvids += ' %s' %p
-                    else:
-                        err += 1
-                        running_bridge_port_pvids += ' %s=%s' %(port,
-                                                            running_pvid)
-                except Exception, e:
-                    self.log_warn('%s: failure checking pvid %s (%s)'
-                            %(ifaceobj.name, pvid, str(e)))
-            if err:
-                ifaceobjcurr.update_config_with_status('bridge-port-pvids',
-                                                 running_bridge_port_pvids, 1)
-            else:
-                ifaceobjcurr.update_config_with_status('bridge-port-pvids',
-                                                 running_bridge_port_pvids, 0)
-
-        # XXX: No need to check for bridge-vids on the bridge
-        # This is used by the ports. The vids on the bridge
-        # come from the vlan interfaces on the bridge.
-        #
-        attrval = ifaceobj.get_attr_value_first('bridge-vids')
-        #if attrval:
-        #    vids = re.split(r'[\s\t]\s*', attrval)
-        #    running_vids = running_vidinfo.get(ifaceobj.name, {}).get('vlan')
-        #    if running_vids:
-        #        if self._compare_vids(vids, running_vids):
-        #            ifaceobjcurr.update_config_with_status('bridge-vids',
-        #                                                   attrval, 0)
-        #        else:
-        #            ifaceobjcurr.update_config_with_status('bridge-vids',
-        #                                        ','.join(running_vids), 1)
-        #    else:
-        #        ifaceobjcurr.update_config_with_status('bridge-vids', attrval,
-        #                                               1)
-        if attrval:
-            ifaceobjcurr.update_config_with_status('bridge-vids', attrval, -1)
-
-    def _query_check_bridge(self, ifaceobj, ifaceobjcurr,
-                            ifaceobj_getfunc=None):
-        if not self._is_bridge(ifaceobj):
-            return
-        if not self.brctlcmd.bridge_exists(ifaceobj.name):
-            self.logger.info('%s: bridge: does not exist' %(ifaceobj.name))
-            return
-
-        ifaceattrs = self.dict_key_subset(ifaceobj.config,
-                                          self.get_mod_attrs())
-        if not ifaceattrs:
-            return
-        try:
-            runningattrs = self.brctlcmd.get_bridge_attrs(ifaceobj.name)
-            if not runningattrs:
-               self.logger.debug('%s: bridge: unable to get bridge attrs'
-                                 %ifaceobj.name)
-               runningattrs = {}
-        except Exception, e:
-            self.logger.warn(str(e))
-            runningattrs = {}
-        filterattrs = ['bridge-vids', 'bridge-port-vids',
-                       'bridge-port-pvids']
-        for k in Set(ifaceattrs).difference(filterattrs):
-            # get the corresponding ifaceobj attr
-            v = ifaceobj.get_attr_value_first(k)
-            if not v:
-               continue
-            rv = runningattrs.get(k[7:])
-            if k == 'bridge-mcqv4src':
-               continue
-            if k == 'bridge-vlan-aware' and v == 'yes':
-                if self.ipcmd.bridge_is_vlan_aware(ifaceobj.name):
-                    ifaceobjcurr.update_config_with_status('bridge-vlan-aware',
-                               v, 0)
-                else:
-                    ifaceobjcurr.update_config_with_status('bridge-vlan-aware',
-                               v, 1)
-            elif k == 'bridge-stp':
-               # special case stp compare because it may
-               # contain more than one valid values
-               stp_on_vals = ['on', 'yes']
-               stp_off_vals = ['off']
-               if ((v in stp_on_vals and rv in stp_on_vals) or
-                   (v in stp_off_vals and rv in stp_off_vals)):
-                    ifaceobjcurr.update_config_with_status('bridge-stp',
-                               v, 0)
-               else:
-                    ifaceobjcurr.update_config_with_status('bridge-stp',
-                                v, 1)
-            elif k == 'bridge-ports':
-               # special case ports because it can contain regex or glob
-               running_port_list = rv.keys() if rv else []
-               bridge_port_list = self._get_bridge_port_list(ifaceobj)
-               if not running_port_list and not bridge_port_list:
-                  continue
-               portliststatus = 1
-               if running_port_list and bridge_port_list:
-                  difference = set(running_port_list
-                                 ).symmetric_difference(bridge_port_list)
-                  if not difference:
-                     portliststatus = 0
-                  ifaceobjcurr.update_config_with_status('bridge-ports',
-                              ' '.join(running_port_list)
-                              if running_port_list else '', portliststatus)
-            elif (k == 'bridge-pathcosts' or
-                  k == 'bridge-portprios' or k == 'bridge-portmcrouter'
-                  or k == 'bridge-portmcfl'):
-               brctlcmdattrname = k[11:].rstrip('s')
-               # for port attributes, the attributes are in a list
-               # <portname>=<portattrvalue>
-               status = 0
-               currstr = ''
-               vlist = self.parse_port_list(v)
-               if not vlist:
-                  continue
-               for vlistitem in vlist:
-                   try:
-                      (p, v) = vlistitem.split('=')
-                      currv = self.brctlcmd.get_bridgeport_attr(
-                                         ifaceobj.name, p,
-                                         brctlcmdattrname)
-                      if currv:
-                          currstr += ' %s=%s' %(p, currv)
-                      else:
-                          currstr += ' %s=%s' %(p, 'None')
-                      if currv != v:
-                          status = 1
-                   except Exception, e:
-                      self.log_warn(str(e))
-                   pass
-               ifaceobjcurr.update_config_with_status(k, currstr, status)
-            elif not rv:
-               ifaceobjcurr.update_config_with_status(k, 'notfound', 1)
-               continue
-            elif v != rv:
-               ifaceobjcurr.update_config_with_status(k, rv, 1)
-            else:
-               ifaceobjcurr.update_config_with_status(k, rv, 0)
-
-        self._query_check_bridge_vidinfo(ifaceobj, ifaceobjcurr)
-
-        self._query_check_mcqv4src(ifaceobj, ifaceobjcurr)
-
-    def _get_bridge_vids(self, bridgename, ifaceobj_getfunc):
-        ifaceobjs = ifaceobj_getfunc(bridgename)
-        for ifaceobj in ifaceobjs:
-            vids = ifaceobj.get_attr_value_first('bridge-vids')
-            if vids: return re.split(r'[\s\t,]\s*', vids)
-        return None
-
-    def _get_bridge_pvid(self, bridgename, ifaceobj_getfunc):
-        ifaceobjs = ifaceobj_getfunc(bridgename)
-        pvid = None
-        for ifaceobj in ifaceobjs:
-            pvid = ifaceobj.get_attr_value_first('bridge-pvid')
-        return pvid
-
-    def _get_bridge_name(self, ifaceobj):
-        return self.ipcmd.bridge_port_get_bridge_name(ifaceobj.name)
-
-    def _query_check_bridge_port_vidinfo(self, ifaceobj, ifaceobjcurr,
-                                         ifaceobj_getfunc, bridgename):
-        running_vidinfo = self._get_running_vidinfo()
-
-        attr_name = 'bridge-access'
-        vids = ifaceobj.get_attr_value_first(attr_name)
-        if vids:
-           running_pvids = running_vidinfo.get(ifaceobj.name,
-                                              {}).get('pvid')
-           running_vids = running_vidinfo.get(ifaceobj.name,
-                                              {}).get('vlan')
-           if (not running_pvids or running_pvids != vids or
-                   running_vids):
-               ifaceobjcurr.update_config_with_status(attr_name,
-                                running_pvids, 1)
-           else:
-               ifaceobjcurr.update_config_with_status(attr_name, vids, 0)
-           return
-
-        attr_name = 'bridge-vids'
-        vids = ifaceobj.get_attr_value_first(attr_name)
-        if vids:
-           vids = re.split(r'[\s\t]\s*', vids)
-           running_vids = running_vidinfo.get(ifaceobj.name,
-                                              {}).get('vlan')
-           if not running_vids or not self._compare_vids(vids, running_vids):
-               ifaceobjcurr.update_config_with_status(attr_name,
-                                ' '.join(running_vids), 1)
-           else:
-               ifaceobjcurr.update_config_with_status(attr_name,
-                                ' '.join(running_vids), 0)
-        else:
-           # check if it matches the bridge vids
-           bridge_vids = self._get_bridge_vids(bridgename, ifaceobj_getfunc)
-           running_vids = running_vidinfo.get(ifaceobj.name,
-                                              {}).get('vlan')
-           if (bridge_vids and (not running_vids  or
-                   not self._compare_vids(bridge_vids, running_vids))):
-              ifaceobjcurr.status = ifaceStatus.ERROR
-              ifaceobjcurr.status_str = 'bridge vid error'
-
-        running_pvid = running_vidinfo.get(ifaceobj.name,
-                                           {}).get('pvid')
-        attr_name = 'bridge-pvid'
-        pvid = ifaceobj.get_attr_value_first(attr_name)
-        if pvid:
-           if running_pvid and running_pvid == pvid:
-              ifaceobjcurr.update_config_with_status(attr_name,
-                                                     running_pvid, 0)
-           else:
-              ifaceobjcurr.update_config_with_status(attr_name,
-                                                     running_pvid, 1)
-        elif not running_pvid or running_pvid != '1':
-           ifaceobjcurr.status = ifaceStatus.ERROR
-           ifaceobjcurr.status_str = 'bridge pvid error'
-
-    def _query_check_bridge_port(self, ifaceobj, ifaceobjcurr,
-                                 ifaceobj_getfunc):
-        if not self._is_bridge_port(ifaceobj):
-            # Mark all bridge attributes as failed
-            ifaceobjcurr.check_n_update_config_with_status_many(ifaceobj,
-                    ['bridge-vids', 'bridge-pvid', 'bridge-access',
-                     'bridge-pathcosts', 'bridge-portprios',
-                     'bridge-portmcrouter',
-                     'bridge-portmcfl'], 1)
-            return
-        bridgename = self._get_bridge_name(ifaceobj)
-        if not bridgename:
-            self.logger.warn('%s: unable to determine bridge name'
-                             %ifaceobj.name)
-            return
-
-        if self.ipcmd.bridge_is_vlan_aware(bridgename):
-            self._query_check_bridge_port_vidinfo(ifaceobj, ifaceobjcurr,
-                                                  ifaceobj_getfunc,
-                                                  bridgename)
-        for attr, dstattr in {'bridge-pathcosts' : 'pathcost',
-                              'bridge-portprios' : 'priority',
-                              'bridge-portmcrouter' : 'mcrouter',
-                              'bridge-portmcfl' : 'mcfl' }.items():
-            attrval = ifaceobj.get_attr_value_first(attr)
-            if not attrval:
-                continue
-
-            try:
-                running_attrval = self.brctlcmd.get_bridgeport_attr(
-                                       bridgename, ifaceobj.name, dstattr)
-                if running_attrval != attrval:
-                    ifaceobjcurr.update_config_with_status(attr,
-                                            running_attrval, 1)
-                else:
-                    ifaceobjcurr.update_config_with_status(attr,
-                                            running_attrval, 0)
-            except Exception, e:
-                self.log_warn('%s: %s' %(ifaceobj.name, str(e)))
-
-    def _query_check(self, ifaceobj, ifaceobjcurr, ifaceobj_getfunc=None):
-        if self._is_bridge(ifaceobj):
-            self._query_check_bridge(ifaceobj, ifaceobjcurr)
-        else:
-            self._query_check_bridge_port(ifaceobj, ifaceobjcurr,
-                                          ifaceobj_getfunc)
-
-    def _query_running_bridge(self, ifaceobjrunning, ifaceobj_getfunc):
-        if self.ipcmd.bridge_is_vlan_aware(ifaceobjrunning.name):
-            ifaceobjrunning.update_config('bridge-vlan-aware', 'yes')
-            ifaceobjrunning.update_config_dict(self._query_running_attrs(
-                                               ifaceobjrunning,
-                                               ifaceobj_getfunc,
-                                               bridge_vlan_aware=True))
-        else: 
-            ifaceobjrunning.update_config_dict(self._query_running_attrs(
-                                               ifaceobjrunning, None))
-
-    def _query_running_bridge_port_attrs(self, ifaceobjrunning, bridgename):
-        if self.sysctl_get('net.bridge.bridge-stp-user-space') == '1':
-            return
-
-        v = self.brctlcmd.get_pathcost(bridgename, ifaceobjrunning.name)
-        if v and v != self.get_mod_subattr('bridge-pathcosts', 'default'):
-            ifaceobjrunning.update_config('bridge-pathcosts', v)
-
-        v = self.brctlcmd.get_pathcost(bridgename, ifaceobjrunning.name)
-        if v and v != self.get_mod_subattr('bridge-portprios', 'default'):
-            ifaceobjrunning.update_config('bridge-portprios', v)
-
-    def _query_running_bridge_port(self, ifaceobjrunning,
-                                   ifaceobj_getfunc=None):
-        bridgename = self.ipcmd.bridge_port_get_bridge_name(
-                                                ifaceobjrunning.name)
-        bridge_vids = None
-        bridge_pvid = None
-        if not bridgename:
-            self.logger.warn('%s: unable to find bridgename'
-                             %ifaceobjrunning.name)
-            return
-        if not self.ipcmd.bridge_is_vlan_aware(bridgename):
-            return
-
-        running_vidinfo = self._get_running_vidinfo()
-        bridge_port_vids = running_vidinfo.get(ifaceobjrunning.name,
-                                               {}).get('vlan')
-        bridge_port_pvid = running_vidinfo.get(ifaceobjrunning.name,
-                                               {}).get('pvid')
-
-        bridgeifaceobjlist = ifaceobj_getfunc(bridgename)
-        if bridgeifaceobjlist:
-           bridge_vids = bridgeifaceobjlist[0].get_attr_value('bridge-vids')
-           bridge_pvid = bridgeifaceobjlist[0].get_attr_value_first('bridge-pvid')
-
-        if not bridge_port_vids and bridge_port_pvid:
-            # must be an access port
-            if bridge_port_pvid != '1':
-               ifaceobjrunning.update_config('bridge-access',
-                                          bridge_port_pvid)
-        else:
-            if bridge_port_vids:
-                if (not bridge_vids or bridge_port_vids != bridge_vids):
-                   ifaceobjrunning.update_config('bridge-vids',
-                                        ' '.join(bridge_port_vids))
-            if bridge_port_pvid and bridge_port_pvid != '1':
-                if (not bridge_pvid or (bridge_port_pvid != bridge_pvid)):
-                    ifaceobjrunning.update_config('bridge-pvid',
-                                        bridge_port_pvid)
-        self._query_running_bridge_port_attrs(ifaceobjrunning, bridgename)
-
-    def _query_running(self, ifaceobjrunning, ifaceobj_getfunc=None):
-        if self.brctlcmd.bridge_exists(ifaceobjrunning.name):
-            self._query_running_bridge(ifaceobjrunning, ifaceobj_getfunc)
-        elif self.brctlcmd.is_bridge_port(ifaceobjrunning.name):
-            self._query_running_bridge_port(ifaceobjrunning, ifaceobj_getfunc)
-
-    _run_ops = {'pre-up' : _up,
-               'post-down' : _down,
-               'query-checkcurr' : _query_check,
-               'query-running' : _query_running}
-
-    def get_ops(self):
-        """ returns list of ops supported by this module """
-        return self._run_ops.keys()
-
-    def _init_command_handlers(self):
-        flags = self.get_flags()
-        if not self.ipcmd:
-            self.ipcmd = iproute2(**flags)
-        if not self.brctlcmd:
-            self.brctlcmd = brctl(**flags)
-
-    def run(self, ifaceobj, operation, query_ifaceobj=None,
-            ifaceobj_getfunc=None):
-        """ run bridge configuration on the interface object passed as
-            argument. Can create bridge interfaces if they dont exist already
-
-        Args:
-            **ifaceobj** (object): iface object
-
-            **operation** (str): any of 'pre-up', 'post-down', 'query-checkcurr',
-                                 'query-running'
-
-        Kwargs:
-            **query_ifaceobj** (object): query check ifaceobject. This is only
-                valid when op is 'query-checkcurr'. It is an object same as
-                ifaceobj, but contains running attribute values and its config
-                status. The modules can use it to return queried running state
-                of interfaces. status is success if the running state is same
-                as user required state in ifaceobj. error otherwise.
-        """
-        op_handler = self._run_ops.get(operation)
-        if not op_handler:
-           return
-        self._init_command_handlers()
-        self._flush_running_vidinfo()
-        if operation == 'query-checkcurr':
-            op_handler(self, ifaceobj, query_ifaceobj,
-                       ifaceobj_getfunc=ifaceobj_getfunc)
-        else:
-            op_handler(self, ifaceobj, ifaceobj_getfunc=ifaceobj_getfunc)
diff --git a/ifupdown2/addons/bridgevlan.py b/ifupdown2/addons/bridgevlan.py
deleted file mode 100644 (file)
index 44824c7..0000000
+++ /dev/null
@@ -1,170 +0,0 @@
-#!/usr/bin/python
-#
-# Copyright 2014 Cumulus Networks, Inc. All rights reserved.
-# Author: Roopa Prabhu, roopa@cumulusnetworks.com
-#
-
-from ifupdown.iface import *
-from ifupdownaddons.modulebase import moduleBase
-from ifupdownaddons.iproute2 import iproute2
-from ifupdownaddons.bridgeutils import brctl
-import logging
-
-class bridgevlan(moduleBase):
-    """  ifupdown2 addon module to configure vlan attributes on a vlan
-         aware bridge """
-
-    _modinfo = {'mhelp' : 'bridgevlan module configures vlan attributes ' +
-                        'on a vlan aware bridge. This module only ' +
-                        'understands vlan interface name ' +
-                        'with dot notations. eg br0.100. where br0 is the ' +
-                        'vlan aware bridge this config is for',
-                'attrs' : {
-                        'bridge-igmp-querier-src' :
-                            { 'help' : 'bridge igmp querier src. Must be ' +
-                                   'specified under the vlan interface',
-                              'example' : ['bridge-igmp-querier-src 172.16.101.1']}}}
-
-    def __init__(self, *args, **kargs):
-        moduleBase.__init__(self, *args, **kargs)
-        self.brctlcmd = None
-        self.ipcmd = None
-
-    def _is_bridge_vlan_device(self, ifaceobj):
-        if ifaceobj.type == ifaceType.BRIDGE_VLAN:
-            return True
-        return False
-
-    def _get_bridge_n_vlan(self, ifaceobj):
-        vlist = ifaceobj.name.split('.', 1)
-        if len(vlist) == 2:
-            return (vlist[0], vlist[1])
-        return None
-
-    def _get_bridgename(self, ifaceobj):
-        vlist = ifaceobj.name.split('.', 1)
-        if len(vlist) == 2:
-            return vlist[0]
-        return None
-
-    def get_dependent_ifacenames(self, ifaceobj, ifaceobjs_all=None):
-        if not self._is_bridge_vlan_device(ifaceobj):
-            return None
-        return [self._get_bridgename(ifaceobj)]
-
-    def _up(self, ifaceobj):
-        try:
-            (bridgename, vlan) = self._get_bridge_n_vlan(ifaceobj)
-            vlanid = int(vlan, 10)
-        except:
-            self.logger.warn('%s: bridge vlan interface name ' %ifaceobj.name +
-                    'does not correspond to format (eg. br0.100)')
-            raise
-
-        if not self.ipcmd.link_exists(bridgename):
-            #self.logger.warn('%s: bridge %s does not exist' %(ifaceobj.name,
-            #                 bridgename))
-            return
-
-        running_mcqv4src = {}
-        if not self.PERFMODE:
-            running_mcqv4src = self.brctlcmd.get_mcqv4src(bridgename)
-        if running_mcqv4src:
-            r_mcqv4src = running_mcqv4src.get(vlan)
-        else:
-            r_mcqv4src = None
-        mcqv4src = ifaceobj.get_attr_value_first('bridge-igmp-querier-src')
-        if not mcqv4src:
-            if r_mcqv4src:
-                self.brctlcmd.del_mcqv4src(bridgename, vlanid)
-            return
-
-        if r_mcqv4src and r_mcqv4src != mcqv4src:
-            self.brctlcmd.del_mcqv4src(bridgename, vlanid)
-            self.brctlcmd.set_mcqv4src(bridgename, vlanid, mcqv4src)
-        else:
-            self.brctlcmd.set_mcqv4src(bridgename, vlanid, mcqv4src)
-
-    def _down(self, ifaceobj):
-        try:
-            (bridgename, vlan) = self._get_bridge_n_vlan(ifaceobj)
-            vlanid = int(vlan, 10)
-        except:
-            self.logger.warn('%s: bridge vlan interface name ' %ifaceobj.name +
-                    'does not correspond to format (eg. br0.100)')
-            raise
-
-        if not self.ipcmd.link_exists(bridgename):
-            #self.logger.warn('%s: bridge %s does not exist' %(ifaceobj.name,
-            #                 bridgename))
-            return
-        mcqv4src = ifaceobj.get_attr_value_first('bridge-igmp-querier-src')
-        if mcqv4src:
-           self.brctlcmd.del_mcqv4src(bridgename, vlanid)
-
-    def _query_running_bridge_igmp_querier_src(self, ifaceobj):
-        (bridgename, vlanid) = ifaceobj.name.split('.')
-        running_mcqv4src = self.brctlcmd.get_mcqv4src(bridgename)
-        if running_mcqv4src:
-           return running_mcqv4src.get(vlanid)
-        return None
-
-    def _query_check(self, ifaceobj, ifaceobjcurr):
-        attrval = ifaceobj.get_attr_value_first('bridge-igmp-querier-src')
-        if attrval:
-            running_mcq = self._query_running_bridge_igmp_querier_src(ifaceobj)
-            if not running_mcq or running_mcq != attrval:
-                ifaceobjcurr.update_config_with_status(
-                        'bridge-igmp-querier-src', running_mcq, 1)
-            else:
-                ifaceobjcurr.update_config_with_status(
-                        'bridge-igmp-querier-src', attrval, 0)
-                ifaceobjcurr.status = ifaceStatus.SUCCESS
-        return
-
-    def _query_running(self, ifaceobjrunning):
-        # XXX not supported
-        return
-
-    _run_ops = {'pre-up' : _up,
-               'post-down' : _down,
-               'query-checkcurr' : _query_check,
-               'query-running' : _query_running}
-
-    def get_ops(self):
-        """ returns list of ops supported by this module """
-        return self._run_ops.keys()
-
-    def _init_command_handlers(self):
-        if not self.ipcmd:
-            self.ipcmd = iproute2(**self.get_flags())
-        if not self.brctlcmd:
-            self.brctlcmd = brctl(**self.get_flags())
-
-    def run(self, ifaceobj, operation, query_ifaceobj=None, **extra_args):
-        """ run vlan configuration on the interface object passed as argument
-
-        Args:
-            **ifaceobj** (object): iface object
-
-            **operation** (str): any of 'pre-up', 'post-down', 'query-checkcurr',
-                                 'query-running'
-        Kwargs:
-            **query_ifaceobj** (object): query check ifaceobject. This is only
-                valid when op is 'query-checkcurr'. It is an object same as
-                ifaceobj, but contains running attribute values and its config
-                status. The modules can use it to return queried running state
-                of interfaces. status is success if the running state is same
-                as user required state in ifaceobj. error otherwise.
-        """
-        op_handler = self._run_ops.get(operation)
-        if not op_handler:
-            return
-        if (operation != 'query-running' and
-                not self._is_bridge_vlan_device(ifaceobj)):
-            return
-        self._init_command_handlers()
-        if operation == 'query-checkcurr':
-            op_handler(self, ifaceobj, query_ifaceobj)
-        else:
-            op_handler(self, ifaceobj)
diff --git a/ifupdown2/addons/dhcp.py b/ifupdown2/addons/dhcp.py
deleted file mode 100644 (file)
index ed68466..0000000
+++ /dev/null
@@ -1,129 +0,0 @@
-#!/usr/bin/python
-#
-# Copyright 2014 Cumulus Networks, Inc. All rights reserved.
-# Author: Roopa Prabhu, roopa@cumulusnetworks.com
-#
-
-try:
-    from ipaddr import IPNetwork
-    from sets import Set
-    from ifupdown.iface import *
-    from ifupdownaddons.modulebase import moduleBase
-    from ifupdownaddons.dhclient import dhclient
-    from ifupdownaddons.iproute2 import iproute2
-except ImportError, e:
-    raise ImportError (str(e) + "- required module not found")
-
-class dhcp(moduleBase):
-    """ ifupdown2 addon module to configure dhcp on interface """
-
-    def __init__(self, *args, **kargs):
-        moduleBase.__init__(self, *args, **kargs)
-        self.dhclientcmd = dhclient(**kargs)
-        self.ipcmd = None
-
-    def _up(self, ifaceobj):
-        try:
-            if ifaceobj.addr_family == 'inet':
-                # First release any existing dhclient processes
-                try:
-                    if not self.PERFMODE:
-                        self.dhclientcmd.stop(ifaceobj.name)
-                except:
-                    pass
-                self.dhclientcmd.start(ifaceobj.name)
-            elif ifaceobj.addr_family == 'inet6':
-                accept_ra = ifaceobj.get_attr_value_first('accept_ra')
-                if accept_ra:
-                    # XXX: Validate value
-                    self.sysctl_set('net.ipv6.conf.%s' %ifaceobj.name +
-                            '.accept_ra', accept_ra)
-                autoconf = ifaceobj.get_attr_value_first('autoconf')
-                if autoconf:
-                    # XXX: Validate value
-                    self.sysctl_set('net.ipv6.conf.%s' %ifaceobj.name +
-                            '.autoconf', autoconf)
-                    try:
-                        self.dhclientcmd.stop6(ifaceobj.name)
-                    except:
-                        pass
-                self.dhclientcmd.start6(ifaceobj.name)
-        except Exception, e:
-            self.log_error(str(e))
-
-    def _down(self, ifaceobj):
-        self.dhclientcmd.release(ifaceobj.name)
-        self.ipcmd.link_down(ifaceobj.name)
-
-    def _query_check(self, ifaceobj, ifaceobjcurr):
-        if self.dhclientcmd.is_running(ifaceobjcurr.name):
-            ifaceobjcurr.addr_family = 'inet'
-            if ifaceobj.addr_family != 'inet':
-                ifaceobjcurr.status = ifaceStatus.ERROR
-            ifaceobjcurr.addr_method = 'dhcp'
-            ifaceobjcurr.status = ifaceStatus.SUCCESS
-        elif self.dhclientcmd.is_running6(ifaceobjcurr.name):
-            ifaceobjcurr.addr_family = 'inet6'
-            if ifaceobj.addr_family != 'inet6':
-                ifaceobjcurr.status = ifaceStatus.ERROR
-            ifaceobjcurr.addr_method = 'dhcp'
-            ifaceobjcurr.status = ifaceStatus.SUCCESS
-        else:
-            ifaceobjcurr.addr_family = None
-            ifaceobjcurr.status = ifaceStatus.ERROR
-
-    def _query_running(self, ifaceobjrunning):
-        if not self.ipcmd.link_exists(ifaceobjrunning.name):
-            return
-        if self.dhclientcmd.is_running(ifaceobjrunning.name):
-            ifaceobjrunning.addr_family = 'inet'
-            ifaceobjrunning.addr_method = 'dhcp'
-        elif self.dhclientcmd.is_running6(ifaceobjrunning.name):
-            ifaceobjrunning.addr_family = 'inet6'
-            ifaceobjrunning.addr_method = 'dhcp6'
-
-    _run_ops = {'up' : _up,
-               'down' : _down,
-               'query-checkcurr' : _query_check,
-               'query-running' : _query_running }
-
-    def get_ops(self):
-        """ returns list of ops supported by this module """
-        return self._run_ops.keys()
-
-    def _init_command_handlers(self):
-        if not self.ipcmd:
-            self.ipcmd = iproute2(**self.get_flags())
-
-    def run(self, ifaceobj, operation, query_ifaceobj=None, **extra_args):
-        """ run dhcp configuration on the interface object passed as argument
-
-        Args:
-            **ifaceobj** (object): iface object
-
-            **operation** (str): any of 'up', 'down', 'query-checkcurr',
-                                 'query-running'
-
-        Kwargs:
-            **query_ifaceobj** (object): query check ifaceobject. This is only
-                valid when op is 'query-checkcurr'. It is an object same as
-                ifaceobj, but contains running attribute values and its config
-                status. The modules can use it to return queried running state
-                of interfaces. status is success if the running state is same
-                as user required state in ifaceobj. error otherwise.
-        """
-        op_handler = self._run_ops.get(operation)
-        if not op_handler:
-            return
-        try:
-            if (operation != 'query-running' and
-                   (ifaceobj.addr_method != 'dhcp' and 
-                       ifaceobj.addr_method != 'dhcp6')):
-                return
-        except:
-            return
-        self._init_command_handlers()
-        if operation == 'query-checkcurr':
-            op_handler(self, ifaceobj, query_ifaceobj)
-        else:
-            op_handler(self, ifaceobj)
diff --git a/ifupdown2/addons/ethtool.py b/ifupdown2/addons/ethtool.py
deleted file mode 100644 (file)
index f578128..0000000
+++ /dev/null
@@ -1,240 +0,0 @@
-#!/usr/bin/python
-#
-# Copyright 2014 Cumulus Networks, Inc. All rights reserved.
-# Author: Roopa Prabhu, roopa@cumulusnetworks.com
-#
-import json
-import ifupdown.policymanager as policymanager
-
-try:
-    from ipaddr import IPNetwork
-    from sets import Set
-    from ifupdown.iface import *
-    from ifupdownaddons.utilsbase import *
-    from ifupdownaddons.modulebase import moduleBase
-    from ifupdownaddons.iproute2 import iproute2
-except ImportError, e:
-    raise ImportError (str(e) + "- required module not found")
-
-class ethtool(moduleBase,utilsBase):
-    """  ifupdown2 addon module to configure ethtool attributes """
-
-    _modinfo = {'mhelp' : 'ethtool configuration module for interfaces',
-                'attrs': {
-                      'link-speed' :
-                            {'help' : 'set link speed',
-                             'example' : ['link-speed 1000'],
-                             'default' : 'varies by platform and port'},
-                      'link-duplex' :
-                            {'help': 'set link duplex',
-                             'example' : ['link-duplex full'],
-                             'validvals' : ['half', 'full'],
-                             'default' : 'full'},
-                      'link-autoneg' :
-                            {'help': 'set autonegotiation',
-                             'example' : ['link-autoneg on'],
-                             'validvals' : ['on', 'off'],
-                             'default' : 'varies by platform and port'}}}
-
-    def __init__(self, *args, **kargs):
-        moduleBase.__init__(self, *args, **kargs)
-        self.ipcmd = None
-
-    def _post_up(self, ifaceobj, operation='post_up'):
-        """
-        _post_up and _pre_down will reset the layer 2 attributes to default policy
-        settings.
-        """
-        if not self.ipcmd.link_exists(ifaceobj.name):
-            return
-        cmd = ''
-        for attr in ['speed', 'duplex', 'autoneg']:
-            # attribute existed before but we must reset to default
-            config_val = ifaceobj.get_attr_value_first('link-%s'%attr)
-            default_val = policymanager.policymanager_api.get_iface_default(
-                module_name='ethtool',
-                ifname=ifaceobj.name,
-                attr='link-%s'%attr)
-
-            # check running values
-            running_val = None
-            if attr == 'autoneg':
-                # we can only get autoneg from ethtool
-                output = self.exec_commandl(['ethtool', ifaceobj.name])
-                running_val = self.get_autoneg(ethtool_output=output)
-            else:
-                running_val = self.read_file_oneline('/sys/class/net/%s/%s' % \
-                                                     (ifaceobj.name, attr))
-            if config_val and config_val == running_val:
-                # running value is what is configured, do nothing
-                continue
-            if not config_val and default_val and default_val == running_val:
-                # nothing configured but the default is running
-                continue
-            # if we got this far, we need to change it
-            if config_val and (config_val != running_val):
-                # if the configured value is not set, set it
-                cmd += ' %s %s' % (attr, config_val)
-            elif default_val and (default_val != running_val):
-                # or if it has a default not equal to running value, set it
-                cmd += ' %s %s' % (attr, default_val)
-            else:
-                # no value set nor default, leave it alone
-                pass
-        if cmd:
-            self.logger.debug('ethtool %s: iface %s cmd is %s' % \
-                              (operation, ifaceobj.name, cmd))
-            try:
-                # we should only be calling ethtool if there
-                # is a speed set or we can find a default speed
-                # because we should only be calling ethtool on swp ports
-                cmd = 'ethtool -s %s %s' %(ifaceobj.name, cmd)
-                self.exec_command(cmd)
-            except Exception, e:
-                ifaceobj.status = ifaceStatus.ERROR
-                self.log_warn('%s: %s' %(ifaceobj.name, str(e)))
-        else:
-            pass
-
-    def _pre_down(self, ifaceobj):
-        pass #self._post_up(ifaceobj,operation="_pre_down")
-
-    def _query_check(self, ifaceobj, ifaceobjcurr):
-        """
-        _query_check() needs to compare the configured (or running)
-        attribute with the running attribute.
-
-        If there is nothing configured, we compare the default attribute with
-        the running attribute and FAIL if they are different.
-        This is because a reboot will lose their running attribute
-        (the default will get set).
-        """
-        for attr in ['speed', 'duplex', 'autoneg']:
-            # autoneg comes from ethtool whereas speed and duplex from /sys/class
-            if attr == 'autoneg':
-                output = self.exec_commandl(['ethtool', ifaceobj.name])
-                running_attr = self.get_autoneg(ethtool_output=output)
-            else:
-                running_attr = self.read_file_oneline('/sys/class/net/%s/%s' % \
-                                                      (ifaceobj.name, attr))
-
-            configured = ifaceobj.get_attr_value_first('link-%s'%attr)
-            default = policymanager.policymanager_api.get_iface_default(
-                module_name='ethtool',
-                ifname=ifaceobj.name,
-                attr='link-%s'%attr)
-
-            # there is a case where there is no running config or
-            # (there is no default and it is not configured).
-            # In this case, we do nothing (e.g. eth0 has only a
-            # default duplex, lo has nothing)
-            if (not running_attr or (not configured and not default)):
-                continue
-
-            # we make sure we can get a running value first
-            if (running_attr and configured and running_attr == configured):
-                # PASS since running is what is configured 
-                ifaceobjcurr.update_config_with_status('link-%s'%attr,
-                                                       running_attr, 0)
-            elif (running_attr and configured and running_attr != configured):
-                # We show a FAIL since it is not the configured or default
-                ifaceobjcurr.update_config_with_status('link-%s'%attr,
-                                                       running_attr, 1)
-            elif (running_attr and default and running_attr == default):
-                # PASS since running is default
-                ifaceobjcurr.update_config_with_status('link-%s'%attr,
-                                                       running_attr, 0)
-            elif (default or configured):
-                # We show a FAIL since it is not the configured or default
-                ifaceobjcurr.update_config_with_status('link-%s'%attr,
-                                                       running_attr, 1)
-        return
-
-    def get_autoneg(self,ethtool_output=None):
-        """
-        get_autoneg simply calls the ethtool command and parses out
-        the autoneg value.
-        """
-        ethtool_attrs = ethtool_output.split()
-        if ('Auto-negotiation:' in ethtool_attrs):
-            return(ethtool_attrs[ethtool_attrs.index('Auto-negotiation:')+1])
-        else:
-            return(None)
-
-    def _query_running(self, ifaceobj, ifaceobj_getfunc=None):
-        """
-        _query_running looks at the speed and duplex from /sys/class
-        and retreives autoneg from ethtool.  We do not report autoneg
-        if speed is not available because this usually means the link is
-        down and the autoneg value is not reliable when the link is down.
-        """
-        # do not bother showing swp ifaces that are not up for the speed
-        # duplex and autoneg are not reliable.
-        if not self.ipcmd.is_link_up(ifaceobj.name):
-            return
-        for attr in ['speed', 'duplex', 'autoneg']:
-            # autoneg comes from ethtool whereas speed and duplex from /sys/class
-            running_attr = None
-            try:
-                if attr == 'autoneg':
-                    output=self.exec_commandl(['ethtool', ifaceobj.name])
-                    running_attr = self.get_autoneg(ethtool_output=output)
-                else:
-                    running_attr = self.read_file_oneline('/sys/class/net/%s/%s' % \
-                                                          (ifaceobj.name, attr))
-            except:
-                # for nonexistent interfaces, we get an error (rc = 256 or 19200)
-                pass
-
-            # show it
-            if (running_attr):
-                ifaceobj.update_config('link-%s'%attr, running_attr)
-
-        return
-
-    _run_ops = {'pre-down' : _pre_down,
-                'post-up' : _post_up,
-                'query-checkcurr' : _query_check,
-                'query-running' : _query_running }
-
-    def get_ops(self):
-        """ returns list of ops supported by this module """
-        return self._run_ops.keys()
-
-    def _init_command_handlers(self):
-        if not self.ipcmd:
-            self.ipcmd = iproute2(**self.get_flags())
-
-    def run(self, ifaceobj, operation, query_ifaceobj=None, **extra_args):
-        """ run ethtool configuration on the interface object passed as
-            argument
-
-        Args:
-            **ifaceobj** (object): iface object
-
-            **operation** (str): any of 'post-up', 'query-checkcurr',
-                'query-running'
-        Kwargs:
-            **query_ifaceobj** (object): query check ifaceobject. This is only
-                valid when op is 'query-checkcurr'. It is an object same as
-                ifaceobj, but contains running attribute values and its config
-                status. The modules can use it to return queried running state
-                of interfaces. status is success if the running state is same
-                as user required state in ifaceobj. error otherwise.
-        """
-        op_handler = self._run_ops.get(operation)
-        if not op_handler:
-            return
-        self._init_command_handlers()
-
-        # check to make sure we are only checking/setting interfaces with
-        # no lower interfaces.   No bridges, no vlans, loopbacks.
-        if ifaceobj.lowerifaces != None or \
-           self.ipcmd.link_isloopback(ifaceobj.name) or \
-           self.ipcmd.is_vlan_device_by_name(ifaceobj.name):
-            return
-
-        if operation == 'query-checkcurr':
-            op_handler(self, ifaceobj, query_ifaceobj)
-        else:
-            op_handler(self, ifaceobj)
diff --git a/ifupdown2/addons/ifenslave.py b/ifupdown2/addons/ifenslave.py
deleted file mode 100644 (file)
index ba37732..0000000
+++ /dev/null
@@ -1,442 +0,0 @@
-#!/usr/bin/python
-#
-# Copyright 2014 Cumulus Networks, Inc. All rights reserved.
-# Author: Roopa Prabhu, roopa@cumulusnetworks.com
-#
-
-from sets import Set
-from ifupdown.iface import *
-import ifupdownaddons
-from ifupdownaddons.modulebase import moduleBase
-from ifupdownaddons.ifenslaveutil import ifenslaveutil
-from ifupdownaddons.iproute2 import iproute2
-import ifupdown.rtnetlink_api as rtnetlink_api
-
-class ifenslave(moduleBase):
-    """  ifupdown2 addon module to configure bond interfaces """
-    _modinfo = { 'mhelp' : 'bond configuration module',
-                    'attrs' : {
-                    'bond-use-carrier':
-                         {'help' : 'bond use carrier',
-                          'validvals' : ['0', '1'],
-                          'default' : '1',
-                          'example': ['bond-use-carrier 1']},
-                     'bond-num-grat-arp':
-                         {'help' : 'bond use carrier',
-                          'validrange' : ['0', '255'],
-                          'default' : '1',
-                          'example' : ['bond-num-grat-arp 1']},
-                     'bond-num-unsol-na' :
-                         {'help' : 'bond slave devices',
-                          'validrange' : ['0', '255'],
-                          'default' : '1',
-                          'example' : ['bond-num-unsol-na 1']},
-                     'bond-xmit-hash-policy' :
-                         {'help' : 'bond slave devices',
-                          'validvals' : ['layer2', 'layer3+4', 'layer2+3'],
-                          'default' : 'layer2',
-                          'example' : ['bond-xmit-hash-policy layer2']},
-                     'bond-miimon' :
-                         {'help' : 'bond miimon',
-                          'validrange' : ['0', '255'],
-                          'default' : '0',
-                          'example' : ['bond-miimon 0']},
-                     'bond-mode' :
-                         {'help' : 'bond mode',
-                          'validvals' : ['balance-rr', 'active-backup',
-                                          'balance-xor', 'broadcast', '802.3ad',
-                                          'balance-tlb', 'balance-alb'],
-                          'default' : 'balance-rr',
-                          'example' : ['bond-mode 802.3ad']},
-                     'bond-lacp-rate':
-                         {'help' : 'bond lacp rate',
-                          'validvals' : ['0', '1'],
-                          'default' : '0',
-                          'example' : ['bond-lacp-rate 0']},
-                     'bond-min-links':
-                         {'help' : 'bond min links',
-                          'default' : '0',
-                          'example' : ['bond-min-links 0']},
-                     'bond-ad-sys-priority':
-                         {'help' : '802.3ad system priority',
-                          'default' : '65535',
-                          'example' : ['bond-ad-sys-priority 65535']},
-                     'bond-ad-sys-mac-addr':
-                         {'help' : '802.3ad system mac address',
-                          'default' : '00:00:00:00:00:00',
-                         'example' : ['bond-ad-sys-mac-addr 00:00:00:00:00:00']},
-                     'bond-lacp-fallback-allow':
-                         {'help' : 'allow lacp fall back',
-                          'compat' : True,
-                          'validvals' : ['0', '1'],
-                          'default' : '0',
-                          'example' : ['bond-lacp-fallback-allow 0']},
-                     'bond-lacp-fallback-period':
-                         {'help' : 'grace period (seconds) for lacp fall back',
-                          'compat' : True,
-                          'validrange' : ['0', '100'],
-                          'default' : '90',
-                          'example' : ['bond-lacp-fallback-period 100']},
-                     'bond-lacp-fallback-priority':
-                         {'help' : 'slave priority for lacp fall back',
-                          'compat' : True,
-                          'example' : ['bond-lacp-fallback-priority swp1=1 swp2=1 swp3=2']},
-                     'bond-lacp-bypass-allow':
-                         {'help' : 'allow lacp bypass',
-                          'validvals' : ['0', '1'],
-                          'default' : '0',
-                          'example' : ['bond-lacp-bypass-allow 0']},
-                     'bond-lacp-bypass-period':
-                         {'help' : 'grace period (seconds) for lacp bypass',
-                          'validrange' : ['0', '900'],
-                          'default' : '0',
-                          'example' : ['bond-lacp-bypass-period 100']},
-                     'bond-lacp-bypass-priority':
-                         {'help' : 'slave priority for lacp bypass',
-                          'example' : ['bond-lacp-bypass-priority swp1=1 swp2=1 swp3=2']},
-                     'bond-slaves' :
-                        {'help' : 'bond slaves',
-                         'required' : True,
-                         'example' : ['bond-slaves swp1 swp2',
-                                      'bond-slaves glob swp1-2',
-                                      'bond-slaves regex (swp[1|2)']}}}
-
-    def __init__(self, *args, **kargs):
-        ifupdownaddons.modulebase.moduleBase.__init__(self, *args, **kargs)
-        self.ipcmd = None
-        self.ifenslavecmd = None
-
-    def _is_bond(self, ifaceobj):
-        if ifaceobj.get_attr_value_first('bond-slaves'):
-            return True
-        return False
-
-    def get_dependent_ifacenames(self, ifaceobj, ifacenames_all=None):
-        """ Returns list of interfaces dependent on ifaceobj """
-
-        if not self._is_bond(ifaceobj):
-            return None
-        slave_list = self.parse_port_list(ifaceobj.get_attr_value_first(
-                                    'bond-slaves'), ifacenames_all)
-        ifaceobj.dependency_type = ifaceDependencyType.MASTER_SLAVE
-        # Also save a copy for future use
-        ifaceobj.priv_data = list(slave_list)
-        if ifaceobj.link_type != ifaceLinkType.LINK_NA:
-           ifaceobj.link_type = ifaceLinkType.LINK_MASTER
-        ifaceobj.link_kind |= ifaceLinkKind.BOND
-        ifaceobj.role |= ifaceRole.MASTER
-
-        return slave_list
-
-    def get_dependent_ifacenames_running(self, ifaceobj):
-        self._init_command_handlers()
-        return self.ifenslavecmd.get_slaves(ifaceobj.name)
-
-    def _get_slave_list(self, ifaceobj):
-        """ Returns slave list present in ifaceobj config """
-
-        # If priv data already has slave list use that first.
-        if ifaceobj.priv_data:
-            return ifaceobj.priv_data
-        slaves = ifaceobj.get_attr_value_first('bond-slaves')
-        if slaves:
-            return self.parse_port_list(slaves)
-        else:
-            return None
-
-    def fetch_attr(self, ifaceobj, attrname):
-        attrval = ifaceobj.get_attr_value_first(attrname)
-        if attrval:
-            msg = ('%s: invalid value %s for attr %s.'
-                    %(ifaceobj.name, attrval, attrname))
-            optiondict = self.get_mod_attr(attrname)
-            if not optiondict:
-                return None
-            validvals = optiondict.get('validvals')
-            if validvals and attrval not in validvals:
-                raise Exception(msg + ' Valid values are %s' %str(validvals))
-            validrange = optiondict.get('validrange')
-            if validrange:
-                if (int(attrval) < int(validrange[0]) or
-                        int(attrval) > int(validrange[1])):
-                    raise Exception(msg + ' Valid range is [%s,%s]'
-                                    %(validrange[0], validrange[1]))
-            if attrname == 'bond-mode' and attrval == '802.3ad':
-               dattrname = 'bond-min-links'
-               min_links = ifaceobj.get_attr_value_first(dattrname)
-               if not min_links or min_links == '0':
-                   self.logger.warn('%s: required attribute %s'
-                        %(ifaceobj.name, dattrname) +
-                        ' not present or set to \'0\'')
-        elif attrname in ['bond-lacp-bypass-allow']:
-            # For some attrs, set default values
-            optiondict = self.get_mod_attr(attrname)
-            if optiondict:
-                return optiondict.get('default')
-        return attrval
-
-    def _apply_master_settings(self, ifaceobj):
-        have_attrs_to_set = 0
-        linkup = False
-        ifenslavecmd_attrmap =  OrderedDict([('bond-mode' , 'mode'),
-                                 ('bond-miimon' , 'miimon'),
-                                 ('bond-use-carrier', 'use_carrier'),
-                                 ('bond-lacp-rate' , 'lacp_rate'),
-                                 ('bond-xmit-hash-policy' , 'xmit_hash_policy'),
-                                 ('bond-min-links' , 'min_links'),
-                                 ('bond-num-grat-arp' , 'num_grat_arp'),
-                                 ('bond-num-unsol-na' , 'num_unsol_na'),
-                                 ('bond-ad-sys-mac-addr' , 'ad_sys_mac_addr'),
-                                 ('bond-ad-sys-priority' , 'ad_sys_priority'),
-                                 ('bond-lacp-fallback-allow', 'lacp_bypass_allow'),
-                                 ('bond-lacp-fallback-period', 'lacp_bypass_period'),
-                                 ('bond-lacp-bypass-allow', 'lacp_bypass_allow'),
-                                 ('bond-lacp-bypass-period', 'lacp_bypass_period')])
-        linkup = self.ipcmd.is_link_up(ifaceobj.name)
-        try:
-            # order of attributes set matters for bond, so
-            # construct the list sequentially
-            attrstoset = OrderedDict()
-            for k, dstk in ifenslavecmd_attrmap.items():
-                v = self.fetch_attr(ifaceobj, k)
-                if v:
-                    attrstoset[dstk] = v
-            if not attrstoset:
-                return
-            have_attrs_to_set = 1
-            self.ifenslavecmd.set_attrs(ifaceobj.name, attrstoset,
-                    self.ipcmd.link_down if linkup else None)
-        except:
-            raise
-        finally:
-            if have_attrs_to_set and linkup:
-                self.ipcmd.link_up(ifaceobj.name)
-
-    def _add_slaves(self, ifaceobj):
-        runningslaves = []
-
-        slaves = self._get_slave_list(ifaceobj)
-        if not slaves:
-            self.logger.debug('%s: no slaves found' %ifaceobj.name)
-            return
-
-        if not self.PERFMODE:
-            runningslaves = self.ifenslavecmd.get_slaves(ifaceobj.name);
-
-        for slave in Set(slaves).difference(Set(runningslaves)):
-            if not self.PERFMODE and not self.ipcmd.link_exists(slave):
-                    self.log_warn('%s: skipping slave %s, does not exist'
-                                  %(ifaceobj.name, slave))
-                    continue
-            link_up = False
-            if self.ipcmd.is_link_up(slave):
-               rtnetlink_api.rtnl_api.link_set(slave, "down")
-               link_up = True
-            self.ipcmd.link_set(slave, 'master', ifaceobj.name)
-            if link_up or ifaceobj.link_type != ifaceLinkType.LINK_NA:
-               try:
-                    rtnetlink_api.rtnl_api.link_set(slave, "up")
-               except Exception, e:
-                    self.logger.debug('%s: %s: link set up (%s)'
-                                      %(ifaceobj.name, slave, str(e)))
-                    pass
-
-        if runningslaves:
-            # Delete active slaves not in the new slave list
-            [ self.ifenslavecmd.remove_slave(ifaceobj.name, s)
-                    for s in runningslaves if s not in slaves ]
-
-    def _set_clag_enable(self, ifaceobj):
-        attrval = ifaceobj.get_attr_value_first('clag-id')
-        attrval = attrval if attrval else '0'
-        self.ifenslavecmd.set_clag_enable(ifaceobj.name, attrval)
-
-    def _apply_slaves_lacp_bypass_prio(self, ifaceobj):
-        slaves = self.ifenslavecmd.get_slaves(ifaceobj.name)
-        if not slaves:
-           return
-        attrval = ifaceobj.get_attrs_value_first(['bond-lacp-bypass-priority',
-                                'bond-lacp-fallback-priority'])
-        if attrval:
-            portlist = self.parse_port_list(attrval)
-            if not portlist:
-                self.log_warn('%s: could not parse \'%s %s\''
-                              %(ifaceobj.name, attrname, attrval))
-                return
-            for p in portlist:
-                try:
-                    (port, val) = p.split('=')
-                    if port not in slaves:
-                        self.log_warn('%s: skipping slave %s, does not exist' 
-                                      %(ifaceobj.name, port))
-                        continue
-                    slaves.remove(port)
-                    self.ifenslavecmd.set_lacp_fallback_priority(
-                                            ifaceobj.name, port, val)
-                except Exception, e:
-                    self.log_warn('%s: failed to set lacp_fallback_priority %s (%s)'
-                                  %(ifaceobj.name, port, str(e)))
-
-        for p in slaves:
-            try:
-                self.ifenslavecmd.set_lacp_fallback_priority(ifaceobj.name, p, '0')
-            except Exception, e:
-                self.log_warn('%s: failed to clear lacp_bypass_priority %s (%s)'
-                              %(ifaceobj.name, p, str(e)))
-
-
-    def _up(self, ifaceobj):
-        try:
-            if not self.ipcmd.link_exists(ifaceobj.name):
-                self.ifenslavecmd.create_bond(ifaceobj.name)
-            self._apply_master_settings(ifaceobj)
-            # clag_enable has to happen before the slaves are added to the bond
-            self._set_clag_enable(ifaceobj)
-            self._add_slaves(ifaceobj)
-            self._apply_slaves_lacp_bypass_prio(ifaceobj)
-            if ifaceobj.addr_method == 'manual':
-               rtnetlink_api.rtnl_api.link_set(ifaceobj.name, "up")
-        except Exception, e:
-            self.log_error(str(e))
-
-    def _down(self, ifaceobj):
-        try:
-            self.ifenslavecmd.delete_bond(ifaceobj.name)
-        except Exception, e:
-            self.log_warn(str(e))
-
-    def _query_check(self, ifaceobj, ifaceobjcurr):
-        slaves = None
-
-        if not self.ifenslavecmd.bond_exists(ifaceobj.name):
-            self.logger.debug('bond iface %s' %ifaceobj.name +
-                              ' does not exist')
-            return
-
-        ifaceattrs = self.dict_key_subset(ifaceobj.config,
-                                          self.get_mod_attrs())
-        if not ifaceattrs: return
-        runningattrs = self._query_running_attrs(ifaceobj.name)
-
-        # backward compat change
-        runningattrs.update({'bond-lacp-fallback-allow': runningattrs.get(
-                                                    'bond-lacp-bypass-allow'),
-                          'bond-lacp-fallback-period': runningattrs.get(
-                                                    'bond-lacp-bypass-period'),
-                          'bond-lacp-fallback-priority': runningattrs.get(
-                                                'bond-lacp-bypass-priority')})
-        for k in ifaceattrs:
-            v = ifaceobj.get_attr_value_first(k)
-            if not v:
-                continue
-            if k == 'bond-slaves':
-                slaves = self._get_slave_list(ifaceobj)
-                continue
-            rv = runningattrs.get(k)
-            if not rv:
-                ifaceobjcurr.update_config_with_status(k, 'None', 1)
-            else:
-                if (k == 'bond-lacp-bypass-priority' or
-                    k == 'bond-lacp-fallback-priority'):
-                    prios = v.split()
-                    prios.sort()
-                    prio_str = ' '.join(prios)
-                    ifaceobjcurr.update_config_with_status(k, rv,
-                                    1 if prio_str != rv else 0)
-                    continue
-                ifaceobjcurr.update_config_with_status(k, rv,
-                                                       1 if v != rv else 0)
-        runningslaves = runningattrs.get('bond-slaves')
-        if not slaves and not runningslaves:
-            return
-        retslave = 1
-        if slaves and runningslaves:
-            if slaves and runningslaves:
-                difference = set(slaves).symmetric_difference(runningslaves)
-                if not difference:
-                    retslave = 0
-        ifaceobjcurr.update_config_with_status('bond-slaves',
-                        ' '.join(runningslaves)
-                        if runningslaves else 'None', retslave)
-
-    def _query_running_attrs(self, bondname):
-        bondattrs = {'bond-mode' :
-                            self.ifenslavecmd.get_mode(bondname),
-                     'bond-miimon' :
-                            self.ifenslavecmd.get_miimon(bondname),
-                     'bond-use-carrier' :
-                            self.ifenslavecmd.get_use_carrier(bondname),
-                     'bond-lacp-rate' :
-                            self.ifenslavecmd.get_lacp_rate(bondname),
-                     'bond-min-links' :
-                            self.ifenslavecmd.get_min_links(bondname),
-                     'bond-ad-sys-mac-addr' :
-                            self.ifenslavecmd.get_ad_sys_mac_addr(bondname),
-                     'bond-ad-sys-priority' :
-                            self.ifenslavecmd.get_ad_sys_priority(bondname),
-                     'bond-xmit-hash-policy' :
-                            self.ifenslavecmd.get_xmit_hash_policy(bondname),
-                     'bond-lacp-bypass-allow' :
-                            self.ifenslavecmd.get_lacp_fallback_allow(bondname),
-                     'bond-lacp-bypass-period' :
-                            self.ifenslavecmd.get_lacp_fallback_period(bondname),
-                     'bond-lacp-bypass-priority' :
-                            self.ifenslavecmd.get_lacp_fallback_priority(bondname)}
-        slaves = self.ifenslavecmd.get_slaves(bondname)
-        if slaves:
-            bondattrs['bond-slaves'] = slaves
-        return bondattrs
-
-    def _query_running(self, ifaceobjrunning):
-        if not self.ifenslavecmd.bond_exists(ifaceobjrunning.name):
-            return
-        bondattrs = self._query_running_attrs(ifaceobjrunning.name)
-        if bondattrs.get('bond-slaves'):
-            bondattrs['bond-slaves'] = ' '.join(bondattrs.get('bond-slaves'))
-        [ifaceobjrunning.update_config(k, v)
-                    for k, v in bondattrs.items()
-                        if v and v != self.get_mod_subattr(k, 'default')]
-
-    _run_ops = {'pre-up' : _up,
-               'post-down' : _down,
-               'query-running' : _query_running,
-               'query-checkcurr' : _query_check}
-
-    def get_ops(self):
-        """ returns list of ops supported by this module """
-        return self._run_ops.keys()
-
-    def _init_command_handlers(self):
-        flags = self.get_flags()
-        if not self.ipcmd:
-            self.ipcmd = iproute2(**flags)
-        if not self.ifenslavecmd:
-            self.ifenslavecmd = ifenslaveutil(**flags)
-
-    def run(self, ifaceobj, operation, query_ifaceobj=None, **extra_args):
-        """ run bond configuration on the interface object passed as argument
-
-        Args:
-            **ifaceobj** (object): iface object
-
-            **operation** (str): any of 'pre-up', 'post-down', 'query-checkcurr',
-                'query-running'
-
-        Kwargs:
-            **query_ifaceobj** (object): query check ifaceobject. This is only
-                valid when op is 'query-checkcurr'. It is an object same as
-                ifaceobj, but contains running attribute values and its config
-                status. The modules can use it to return queried running state
-                of interfaces. status is success if the running state is same
-                as user required state in ifaceobj. error otherwise.
-        """
-        op_handler = self._run_ops.get(operation)
-        if not op_handler:
-            return
-        if operation != 'query-running' and not self._is_bond(ifaceobj):
-            return
-        self._init_command_handlers()
-        if operation == 'query-checkcurr':
-            op_handler(self, ifaceobj, query_ifaceobj)
-        else:
-            op_handler(self, ifaceobj)
diff --git a/ifupdown2/addons/loopback.py b/ifupdown2/addons/loopback.py
deleted file mode 100644 (file)
index dd35917..0000000
+++ /dev/null
@@ -1,63 +0,0 @@
-#!/usr/bin/python
-
-# This should be pretty simple and might not really even need to exist.
-# The key is that we need to call link_create with a type of "dummy"
-# since that will translate to 'ip link add loopbackX type dummy'
-# The config file should probably just indicate that the type is
-# loopback or dummy.
-
-from ifupdown.iface import *
-from ifupdownaddons.modulebase import moduleBase
-from ifupdownaddons.iproute2 import iproute2
-import logging
-
-class loopback(moduleBase):
-    _modinfo = {'mhelp' : 'configure extra loopback module based on ' +
-                         'dummy device' }
-
-    def __init__(self, *args, **kargs):
-        moduleBase.__init__(self, *args, **kargs)
-        self.ipcmd = None
-
-    def _is_loopback_by_name(self, ifacename):
-        return 'loop' in ifacename
-
-    def _up(self, ifaceobj):
-        if self._is_loopback_by_name(ifaceobj.name):
-           self.ipcmd.link_create(ifaceobj.name, 'dummy')
-
-    def _down(self, ifaceobj):
-        if not self.PERFMODE and not self.ipcmd.link_exists(ifaceobj.name):
-           return
-        try:
-            self.ipcmd.link_delete(ifaceobj.name)
-        except Exception, e:
-            self.log_warn(str(e))
-
-    def _query_check(self, ifaceobj, ifaceobjcurr):
-        if not self.ipcmd.link_exists(ifaceobj.name):
-           return
-
-    _run_ops = {'pre-up' : _up,
-               'post-down' : _down,
-               'query-checkcurr' : _query_check}
-
-    def get_ops(self):
-        return self._run_ops.keys()
-
-    def _init_command_handlers(self):
-        if not self.ipcmd:
-            self.ipcmd = iproute2(**self.get_flags())
-
-    def run(self, ifaceobj, operation, query_ifaceobj=None, **extra_args):
-        op_handler = self._run_ops.get(operation)
-        if not op_handler:
-            return
-        if (operation != 'query-running' and
-                not self._is_loopback_by_name(ifaceobj.name)):
-            return
-        self._init_command_handlers()
-        if operation == 'query-checkcurr':
-            op_handler(self, ifaceobj, query_ifaceobj)
-        else:
-            op_handler(self, ifaceobj)
diff --git a/ifupdown2/addons/mstpctl.py b/ifupdown2/addons/mstpctl.py
deleted file mode 100644 (file)
index bc2cd07..0000000
+++ /dev/null
@@ -1,771 +0,0 @@
-#!/usr/bin/python
-#
-# Copyright 2014 Cumulus Networks, Inc. All rights reserved.
-# Author: Roopa Prabhu, roopa@cumulusnetworks.com
-#
-
-from sets import Set
-from ifupdown.iface import *
-from ifupdownaddons.modulebase import moduleBase
-from ifupdownaddons.bridgeutils import brctl
-from ifupdownaddons.iproute2 import iproute2
-from ifupdownaddons.mstpctlutil import mstpctlutil
-import traceback
-
-class mstpctlFlags:
-    PORT_PROCESSED = 0x1
-
-class mstpctl(moduleBase):
-    """  ifupdown2 addon module to configure mstp attributes """
-
-    _modinfo = {'mhelp' : 'mstp configuration module for bridges',
-                'attrs' : {
-                   'mstpctl-ports' :
-                        {'help' : 'mstp ports',
-                         'compat' : True},
-                   'mstpctl-stp' :
-                        {'help': 'bridge stp yes/no',
-                         'compat' : True,
-                         'default' : 'no'},
-                   'mstpctl-treeprio' :
-                        {'help': 'tree priority',
-                         'default' : '32768',
-                         'validrange' : ['0', '65535'],
-                         'required' : False,
-                         'example' : ['mstpctl-treeprio 32768']},
-                   'mstpctl-ageing' :
-                        {'help': 'ageing time',
-                         'default' : '300',
-                         'required' : False,
-                         'example' : ['mstpctl-ageing 300']},
-                    'mstpctl-maxage' :
-                        { 'help' : 'max message age',
-                          'default' : '20',
-                          'required' : False,
-                          'example' : ['mstpctl-maxage 20']},
-                    'mstpctl-fdelay' :
-                        { 'help' : 'set forwarding delay',
-                          'default' : '15',
-                          'required' : False,
-                          'example' : ['mstpctl-fdelay 15']},
-                    'mstpctl-maxhops' :
-                        { 'help' : 'bridge max hops',
-                          'default' : '15',
-                          'required' : False,
-                          'example' : ['mstpctl-maxhops 15']},
-                    'mstpctl-txholdcount' :
-                        { 'help' : 'bridge transmit holdcount',
-                          'default' : '6',
-                          'required' : False,
-                          'example' : ['mstpctl-txholdcount 6']},
-                    'mstpctl-forcevers' :
-                        { 'help' : 'bridge force stp version',
-                          'default' : 'rstp',
-                          'required' : False,
-                          'example' : ['mstpctl-forcevers rstp']},
-                    'mstpctl-portpathcost' :
-                        { 'help' : 'bridge port path cost',
-                          'default' : '0',
-                          'required' : False,
-                          'example' : ['mstpctl-portpathcost swp1=0 swp2=1']},
-                    'mstpctl-portp2p' :
-                        { 'help' : 'bridge port p2p detection mode',
-                          'default' : 'auto',
-                          'validvals' : ['yes', 'no', 'auto'],
-                          'required' : False,
-                          'example' : ['mstpctl-portp2p swp1=no swp2=no']},
-                    'mstpctl-portrestrrole' :
-                        { 'help' :
-                          'enable/disable port ability to take root role of the port',
-                          'default' : 'no',
-                          'validvals' : ['yes', 'no'],
-                          'required' : False,
-                          'example' : ['mstpctl-portrestrrole swp1=no swp2=no']},
-                    'mstpctl-portrestrtcn' :
-                        { 'help' :
-                          'enable/disable port ability to propagate received topology change notification of the port',
-                          'default' : 'no',
-                          'validvals' : ['yes', 'no'],
-                          'required' : False,
-                          'example' : ['mstpctl-portrestrtcn swp1=no swp2=no']},
-                    'mstpctl-bpduguard' :
-                        { 'help' :
-                          'enable/disable bpduguard',
-                          'default' : 'no',
-                          'validvals' : ['yes', 'no'],
-                          'required' : False,
-                          'example' : ['mstpctl-bpduguard swp1=no swp2=no']},
-                    'mstpctl-treeportprio' : 
-                        { 'help' :
-                          'port priority for MSTI instance',
-                          'default' : '128',
-                          'validrange' : ['0', '240'],
-                          'required' : False,
-                          'example' : ['mstpctl-treeportprio swp1=128 swp2=128']},
-                    'mstpctl-hello' :
-                        { 'help' : 'set hello time',
-                          'default' : '2',
-                          'required' : False,
-                          'example' : ['mstpctl-hello 2']},
-                    'mstpctl-portnetwork' : 
-                        { 'help' : 'enable/disable bridge assurance capability for a port',
-                          'validvals' : ['yes', 'no'],
-                          'default' : 'no',
-                          'required' : False,
-                          'example' : ['mstpctl-portnetwork swp1=no swp2=no']},
-                    'mstpctl-portadminedge' : 
-                        { 'help' : 'enable/disable initial edge state of the port',
-                          'validvals' : ['yes', 'no'],
-                          'default' : 'no',
-                          'required' : False,
-                          'example' : ['mstpctl-portadminedge swp1=no swp2=no']},
-                    'mstpctl-portautoedge' : 
-                        { 'help' : 'enable/disable auto transition to/from edge state of the port',
-                          'validvals' : ['yes', 'no'],
-                          'default' : 'yes',
-                          'required' : False,
-                          'example' : ['mstpctl-portautoedge swp1=yes swp2=yes']},
-                    'mstpctl-treeportcost' : 
-                        { 'help' : 'port tree cost',
-                          'required' : False},
-                    'mstpctl-portbpdufilter' : 
-                        { 'help' : 'enable/disable bpdu filter on a port. ' +
-                                'syntax varies when defined under a bridge ' +
-                                'vs under a port',
-                          'validvals' : ['yes', 'no'],
-                          'default' : 'no',
-                          'required' : False,
-                          'example' : ['under a bridge: mstpctl-portbpdufilter swp1=no swp2=no',
-                                       'under a port: mstpctl-portbpdufilter yes']},
-                        }}
-
-    # Maps mstp bridge attribute names to corresponding mstpctl commands
-    # XXX: This can be encoded in the modules dict above
-    _attrs_map = OrderedDict([('mstpctl-treeprio' , 'treeprio'),
-                  ('mstpctl-ageing' , 'ageing'),
-                  ('mstpctl-maxage' , 'maxage'),
-                  ('mstpctl-fdelay' , 'fdelay'),
-                  ('mstpctl-maxhops' , 'maxhops'),
-                  ('mstpctl-txholdcount' , 'txholdcount'),
-                  ('mstpctl-forcevers', 'forcevers'),
-                  ('mstpctl-hello' , 'hello')])
-
-    # Maps mstp port attribute names to corresponding mstpctl commands
-    # XXX: This can be encoded in the modules dict above
-    _port_attrs_map = {'mstpctl-portpathcost' : 'portpathcost',
-                 'mstpctl-portadminedge' : 'portadminedge',
-                 'mstpctl-portautoedge' : 'portautoedge' ,
-                 'mstpctl-portp2p' : 'portp2p',
-                 'mstpctl-portrestrrole' : 'portrestrrole',
-                 'mstpctl-portrestrtcn' : 'portrestrtcn',
-                 'mstpctl-bpduguard' : 'bpduguard',
-                 'mstpctl-treeportprio' : 'treeportprio',
-                 'mstpctl-treeportcost' : 'treeportcost',
-                 'mstpctl-portnetwork' : 'portnetwork',
-                 'mstpctl-portbpdufilter' : 'portbpdufilter'}
-
-    def __init__(self, *args, **kargs):
-        moduleBase.__init__(self, *args, **kargs)
-        self.ipcmd = None
-        self.name = self.__class__.__name__
-        self.brctlcmd = None
-        self.mstpctlcmd = None
-
-    def _is_bridge(self, ifaceobj):
-        if (ifaceobj.get_attr_value_first('mstpctl-ports') or
-                ifaceobj.get_attr_value_first('bridge-ports')):
-            return True
-        return False
-
-    def _is_bridge_port(self, ifaceobj):
-        if self.brctlcmd.is_bridge_port(ifaceobj.name):
-            return True
-        return False
-
-    def get_dependent_ifacenames(self, ifaceobj, ifacenames_all=None):
-        if not self._is_bridge(ifaceobj):
-            return None
-        return self.parse_port_list(ifaceobj.get_attr_value_first(
-                                    'mstpctl-ports'), ifacenames_all)
-
-    def get_dependent_ifacenames_running(self, ifaceobj):
-        self._init_command_handlers()
-        if (self.brctlcmd.bridge_exists(ifaceobj.name) and
-                not self.mstpctlcmd.mstpbridge_exists(ifaceobj.name)):
-            return None
-        return self.brctlcmd.get_bridge_ports(ifaceobj.name)
-
-    def _get_bridge_port_list(self, ifaceobj):
-
-        # port list is also available in the previously
-        # parsed dependent list. Use that if available, instead
-        # of parsing port expr again
-        port_list = ifaceobj.lowerifaces
-        if port_list:
-            return port_list
-        ports = ifaceobj.get_attr_value_first('mstpctl-ports')
-        if ports:
-            return self.parse_port_list(ports)
-        else:
-            return None
-
-    def _ports_enable_disable_ipv6(self, ports, enable='1'):
-        for p in ports:
-            try:
-                self.write_file('/proc/sys/net/ipv6/conf/%s' %p +
-                                '/disable_ipv6', enable)
-            except Exception, e:
-                self.logger.info(str(e))
-                pass
-
-    def _add_ports(self, ifaceobj):
-        bridgeports = self._get_bridge_port_list(ifaceobj)
-
-        runningbridgeports = []
-        # Delete active ports not in the new port list
-        if not self.PERFMODE:
-            runningbridgeports = self.brctlcmd.get_bridge_ports(ifaceobj.name)
-            if runningbridgeports:
-                [self.ipcmd.link_set(bport, 'nomaster')
-                    for bport in runningbridgeports
-                        if not bridgeports or bport not in bridgeports]
-            else:
-                runningbridgeports = []
-        if not bridgeports:
-            return
-        err = 0
-        for bridgeport in Set(bridgeports).difference(Set(runningbridgeports)):
-            try:
-                if not self.DRYRUN and not self.ipcmd.link_exists(bridgeport):
-                    self.log_warn('%s: bridge port %s does not exist'
-                            %(ifaceobj.name, bridgeport))
-                    err += 1
-                    continue
-                self.ipcmd.link_set(bridgeport, 'master', ifaceobj.name)
-                self.ipcmd.addr_flush(bridgeport)
-            except Exception, e:
-                self.log_error(str(e))
-
-        if err:
-            self.log_error('error configuring bridge (missing ports)')
-
-    def _apply_bridge_settings(self, ifaceobj):
-        check = False if self.PERFMODE else True
-        try:
-            # set bridge attributes
-            for attrname, dstattrname in self._attrs_map.items():
-                try:
-                    v = ifaceobj.get_attr_value_first(attrname)
-                    if not v:
-                       continue
-                    if attrname == 'mstpctl-treeprio':
-                       self.mstpctlcmd.set_bridge_treeprio(ifaceobj.name,
-                                v, check)
-                    else:
-                       self.mstpctlcmd.set_bridge_attr(ifaceobj.name,
-                                dstattrname, v, check)
-                except Exception, e:
-                    self.logger.warn('%s' %str(e))
-                    pass
-
-            # set bridge port attributes
-            for attrname, dstattrname in self._port_attrs_map.items():
-                attrval = ifaceobj.get_attr_value_first(attrname)
-                if not attrval:
-                    continue
-                portlist = self.parse_port_list(attrval)
-                if not portlist:
-                    self.log_warn('%s: error parsing \'%s %s\''
-                         %(ifaceobj.name, attrname, attrval))
-                    continue
-                for p in portlist:
-                    try:
-                        (port, val) = p.split('=')
-                        self.mstpctlcmd.set_bridgeport_attr(ifaceobj.name,
-                                port, dstattrname, val, check)
-                    except Exception, e:
-                        self.log_warn('%s: error setting %s (%s)'
-                                %(ifaceobj.name, attrname, str(e)))
-        except Exception, e:
-            self.log_warn(str(e))
-            pass
-
-    def _apply_bridge_port_settings(self, ifaceobj, bridgename=None,
-                                    bridgeifaceobj=None, stp_on=True,
-                                    mstpd_running=True):
-        check = False if self.PERFMODE else True
-        if not bridgename and bridgeifaceobj:
-            bridgename = bridgeifaceobj.name
-        # set bridge port attributes
-        for attrname, dstattrname in self._port_attrs_map.items():
-            attrval = ifaceobj.get_attr_value_first(attrname)
-            if not attrval:
-               #if bridgeifaceobj:
-               #   # If bridge object available, check if the bridge
-               #   # has the attribute set, in which case,
-               #   # inherit it from the bridge
-               #   attrval = bridgeifaceobj.get_attr_value_first(attrname)
-               #   if not attrval:
-               #      continue
-               #else:
-               continue
-            if not stp_on:
-               self.logger.warn('%s: cannot set %s (stp on bridge %s not on)\n'
-                       %(ifaceobj.name, attrname, bridgename))
-               continue
-            if not mstpd_running:
-               continue
-            try:
-               self.mstpctlcmd.set_bridgeport_attr(bridgename,
-                           ifaceobj.name, dstattrname, attrval, check)
-            except Exception, e:
-               self.log_warn('%s: error setting %s (%s)'
-                             %(ifaceobj.name, attrname, str(e)))
-
-    def _apply_bridge_port_settings_all(self, ifaceobj,
-                                        ifaceobj_getfunc=None):
-        self.logger.info('%s: applying mstp configuration '
-                          %ifaceobj.name + 'specific to ports')
-        # Query running bridge ports. and only apply attributes on them
-        bridgeports = self.brctlcmd.get_bridge_ports(ifaceobj.name)
-        if not bridgeports:
-           self.logger.debug('%s: cannot find bridgeports' %ifaceobj.name)
-           return
-        for bport in bridgeports:
-            self.logger.info('%s: processing mstp config for port %s'
-                             %(ifaceobj.name, bport))
-            if not self.ipcmd.link_exists(bport):
-               continue
-            bportifaceobjlist = ifaceobj_getfunc(bport)
-            if not bportifaceobjlist:
-               continue
-            for bportifaceobj in bportifaceobjlist:
-                # Dont process bridge port if it already has been processed
-                if (bportifaceobj.module_flags.get(self.name,0x0) & \
-                    mstpctlFlags.PORT_PROCESSED):
-                    continue
-                try:
-                    self._apply_bridge_port_settings(bportifaceobj, 
-                                            ifaceobj.name, ifaceobj)
-                except Exception, e:
-                    self.log_warn(str(e))
-
-    def _up(self, ifaceobj, ifaceobj_getfunc=None):
-        # Check if bridge port
-        bridgename = self.ipcmd.bridge_port_get_bridge_name(ifaceobj.name)
-        if bridgename:
-            mstpd_running = (True if self.mstpctlcmd.is_mstpd_running()
-                             else False)
-            stp_on = (True if self.read_file_oneline(
-                      '/sys/class/net/%s/bridge/stp_state'
-                      %bridgename) == '2' else False)
-            self._apply_bridge_port_settings(ifaceobj, bridgename, None,
-                                             stp_on, mstpd_running)
-            ifaceobj.module_flags[self.name] = ifaceobj.module_flags.setdefault(self.name,0) | \
-                                               mstpctlFlags.PORT_PROCESSED
-            return
-        if not self._is_bridge(ifaceobj):
-            return
-        stp = None
-        try:
-            porterr = False
-            porterrstr = ''
-            if ifaceobj.get_attr_value_first('mstpctl-ports'):
-                # If bridge ports specified with mstpctl attr, create the
-                # bridge and also add its ports
-                self.ipcmd.batch_start()
-                if not self.PERFMODE:
-                    if not self.ipcmd.link_exists(ifaceobj.name):
-                        self.ipcmd.link_create(ifaceobj.name, 'bridge')
-                else:
-                    self.ipcmd.link_create(ifaceobj.name, 'bridge')
-                try:
-                    self._add_ports(ifaceobj)
-                except Exception, e:
-                    porterr = True
-                    porterrstr = str(e)
-                    pass
-                finally:
-                    self.ipcmd.batch_commit()
-            running_ports = self.brctlcmd.get_bridge_ports(ifaceobj.name)
-            if running_ports:
-                # disable ipv6 for ports that were added to bridge
-                self._ports_enable_disable_ipv6(running_ports, '1')
-
-            stp = ifaceobj.get_attr_value_first('mstpctl-stp')
-            if stp:
-               self.set_iface_attr(ifaceobj, 'mstpctl-stp',
-                                    self.brctlcmd.set_stp)
-            else:
-               stp = self.brctlcmd.get_stp(ifaceobj.name)
-            if (self.mstpctlcmd.is_mstpd_running() and
-                    (stp == 'yes' or stp == 'on')):
-                self._apply_bridge_settings(ifaceobj)
-                self._apply_bridge_port_settings_all(ifaceobj,
-                            ifaceobj_getfunc=ifaceobj_getfunc)
-        except Exception, e:
-            self.log_error(str(e))
-        if porterr:
-            raise Exception(porterrstr)
-
-    def _down(self, ifaceobj, ifaceobj_getfunc=None):
-        if not self._is_bridge(ifaceobj):
-            return
-        try:
-            if ifaceobj.get_attr_value_first('mstpctl-ports'):
-                # If bridge ports specified with mstpctl attr, delete the
-                # bridge
-                ports = self.brctlcmd.get_bridge_ports(ifaceobj.name)
-                if ports:
-                    self._ports_enable_disable_ipv6(ports, '0')
-                self.brctlcmd.delete_bridge(ifaceobj.name)
-        except Exception, e:
-            self.log_error(str(e))
-
-    def _query_running_attrs(self, ifaceobjrunning):
-        bridgeattrdict = {}
-
-        tmpbridgeattrdict = self.mstpctlcmd.get_bridge_attrs(ifaceobjrunning.name)
-        if not tmpbridgeattrdict:
-            return bridgeattrdict
-
-        for k,v in tmpbridgeattrdict.items():
-            if k == 'stp' or not v:
-                continue
-            if k == 'ports':
-                ports = v.keys()
-                continue
-            attrname = 'mstpctl-' + k
-            if v and v != self.get_mod_subattr(attrname, 'default'):
-                bridgeattrdict[attrname] = [v]
-
-        ports = self.brctlcmd.get_bridge_ports(ifaceobjrunning.name)
-        if ports:
-            portconfig = {'mstpctl-portnetwork' : '',
-                          'mstpctl-portpathcost' : '',
-                          'mstpctl-portadminedge' : '',
-                          'mstpctl-portautoedge' : '',
-                          'mstpctl-portp2p' : '',
-                          'mstpctl-portrestrrole' : '',
-                          'mstpctl-portrestrtcn' : '',
-                          'mstpctl-bpduguard' : '',
-                          'mstpctl-treeportprio' : '',
-                          'mstpctl-treeportcost' : ''}
-
-            for p in ports:
-                v = self.mstpctlcmd.get_bridgeport_attr(ifaceobjrunning.name,
-                            p, 'portnetwork')
-                if v and v != 'no':
-                    portconfig['mstpctl-portnetwork'] += ' %s=%s' %(p, v)
-
-                # XXX: Can we really get path cost of a port ???
-                #v = self.mstpctlcmd.get_portpathcost(ifaceobjrunning.name, p)
-                #if v and v != self.get_mod_subattr('mstpctl-portpathcost',
-                #                                   'default'):
-                #    portconfig['mstpctl-portpathcost'] += ' %s=%s' %(p, v)
-
-                v = self.mstpctlcmd.get_bridgeport_attr(ifaceobjrunning.name,
-                            p, 'portadminedge')
-                if v and v != 'no':
-                    portconfig['mstpctl-portadminedge'] += ' %s=%s' %(p, v)
-
-                v = self.mstpctlcmd.get_bridgeport_attr(ifaceobjrunning.name,
-                            p, 'portp2p')
-                if v and v != 'no':
-                    portconfig['mstpctl-portp2p'] += ' %s=%s' %(p, v)
-
-                v = self.mstpctlcmd.get_bridgeport_attr(ifaceobjrunning.name,
-                            p, 'portrestrrole')
-                if v and v != 'no':
-                    portconfig['mstpctl-portrestrrole'] += ' %s=%s' %(p, v)
-
-                v = self.mstpctlcmd.get_bridgeport_attr(ifaceobjrunning.name,
-                            p, 'portrestrtcn')
-                if v and v != 'no':
-                    portconfig['mstpctl-portrestrtcn'] += ' %s=%s' %(p, v)
-
-                v = self.mstpctlcmd.get_bridgeport_attr(ifaceobjrunning.name,
-                            p, 'bpduguard')
-                if v and v != 'no':
-                    portconfig['mstpctl-bpduguard'] += ' %s=%s' %(p, v)
-
-                # XXX: Can we really get path cost of a port ???
-                #v = self.mstpctlcmd.get_bridgeport_attr(ifaceobjrunning.name,
-                #            p, 'treeprio')
-                #if v and v != self.get_mod_subattr('mstpctl-treeportprio',
-                #                                   'default'):
-                #    portconfig['mstpctl-treeportprio'] += ' %s=%s' %(p, v)
-
-                #v = self.mstpctlcmd.get_bridgeport_attr(ifaceobjrunning.name,
-                #            p, 'treecost')
-                #if v and v != self.get_mod_subattr('mstpctl-treeportcost',
-                #                                   'default'):
-                #    portconfig['mstpctl-treeportcost'] += ' %s=%s' %(p, v)
-
-            bridgeattrdict.update({k : [v] for k, v in portconfig.items()
-                                    if v})
-        return bridgeattrdict
-
-    def _query_check_bridge(self, ifaceobj, ifaceobjcurr):
-        # list of attributes that are not supported currently
-        blacklistedattrs = ['mstpctl-portpathcost',
-                'mstpctl-treeportprio', 'mstpctl-treeportcost']
-        if not self.brctlcmd.bridge_exists(ifaceobj.name):
-            self.logger.debug('bridge %s does not exist' %ifaceobj.name)
-            return
-        ifaceattrs = self.dict_key_subset(ifaceobj.config,
-                                          self.get_mod_attrs())
-        if not ifaceattrs:
-            return
-        runningattrs = self.mstpctlcmd.get_bridge_attrs(ifaceobj.name)
-        if not runningattrs:
-            runningattrs = {}
-        for k in ifaceattrs:
-            # for all mstpctl options
-            if k in blacklistedattrs:
-                continue
-            # get the corresponding ifaceobj attr
-            v = ifaceobj.get_attr_value_first(k)
-            if not v:
-                continue
-
-            # Get the running attribute
-            rv = runningattrs.get(k[8:])
-            if k == 'mstpctl-stp':
-                # special case stp compare because it may
-                # contain more than one valid values
-                stp_on_vals = ['on', 'yes']
-                stp_off_vals = ['off']
-                rv = self.brctlcmd.get_stp(ifaceobj.name)
-                if ((v in stp_on_vals and rv in stp_on_vals) or
-                    (v in stp_off_vals and rv in stp_off_vals)):
-                    ifaceobjcurr.update_config_with_status('mstpctl-stp', v, 0)
-                else:
-                    ifaceobjcurr.update_config_with_status('mstpctl-stp', v, 1)
-                continue
-
-            if k == 'mstpctl-ports':
-                # special case ports because it can contain regex or glob
-                # XXX: We get all info from mstputils, which means if
-                # mstpd is down, we will not be returning any bridge bridgeports
-                running_port_list = self.brctlcmd.get_bridge_ports(ifaceobj.name)
-                bridge_port_list = self._get_bridge_port_list(ifaceobj)
-                if not running_port_list and not bridge_port_list:
-                    continue
-                portliststatus = 1
-                if running_port_list and bridge_port_list:
-                    difference = Set(running_port_list).symmetric_difference(
-                                                        Set(bridge_port_list))
-                    if not difference:
-                        portliststatus = 0
-                ifaceobjcurr.update_config_with_status('mstpctl-ports',
-                    ' '.join(running_port_list)
-                    if running_port_list else '', portliststatus)
-            elif k[:12] == 'mstpctl-port' or k == 'mstpctl-bpduguard':
-                # Now, look at port attributes
-                # derive the mstpctlcmd attr name
-                #mstpctlcmdattrname = k[12:] if k[:12] == 'mstpctl-port' else k[8:]
-                mstpctlcmdattrname = k[8:]
-
-                # for port attributes, the attributes are in a list
-                # <portname>=<portattrvalue>
-                status = 0
-                currstr = ''
-                vlist = self.parse_port_list(v)
-                if not vlist:
-                    continue
-                for vlistitem in vlist:
-                    try:
-                        (p, v) = vlistitem.split('=')
-                        currv = self.mstpctlcmd.get_bridgeport_attr(
-                                        ifaceobj.name, p, mstpctlcmdattrname)
-                        if currv:
-                            currstr += ' %s=%s' %(p, currv)
-                        else:
-                            currstr += ' %s=%s' %(p, 'None')
-                        if currv != v:
-                            status = 1
-                    except Exception, e:
-                        self.log_warn(str(e))
-                        pass
-                ifaceobjcurr.update_config_with_status(k, currstr, status)
-            elif not rv:
-                ifaceobjcurr.update_config_with_status(k, '', 1)
-            elif v != rv:
-                ifaceobjcurr.update_config_with_status(k, rv, 1)
-            else:
-                ifaceobjcurr.update_config_with_status(k, rv, 0)
-
-    def _query_check_bridge_port(self, ifaceobj, ifaceobjcurr):
-        if not self.ipcmd.link_exists(ifaceobj.name):
-            #self.logger.debug('bridge port %s does not exist' %ifaceobj.name)
-            ifaceobjcurr.status = ifaceStatus.NOTFOUND
-            return
-        # Check if this is a bridge port
-        if not self._is_bridge_port(ifaceobj):
-            # mark all the bridge attributes as error
-            ifaceobjcurr.check_n_update_config_with_status_many(ifaceobj,
-                            self._port_attrs_map.keys(), 0)
-            return
-        bridgename = self.ipcmd.bridge_port_get_bridge_name(ifaceobj.name)
-        # list of attributes that are not supported currently
-        blacklistedattrs = ['mstpctl-portpathcost',
-                'mstpctl-treeportprio', 'mstpctl-treeportcost']
-        ifaceattrs = self.dict_key_subset(ifaceobj.config,
-                                          self._port_attrs_map.keys())
-        if not ifaceattrs:
-            return
-        runningattrs = self.mstpctlcmd.get_bridge_attrs(ifaceobj.name)
-        if not runningattrs:
-            runningattrs = {}
-        for k in ifaceattrs:
-            # for all mstpctl options
-            # get the corresponding ifaceobj attr
-            v = ifaceobj.get_attr_value_first(k)
-            if not v or k in blacklistedattrs:
-                ifaceobjcurr.update_config_with_status(k, v, -1)
-                continue
-            currv = self.mstpctlcmd.get_bridgeport_attr(bridgename,
-                             ifaceobj.name, self._port_attrs_map.get(k))
-            if currv:
-                if currv != v:
-                    ifaceobjcurr.update_config_with_status(k, currv, 1)
-                else:
-                    ifaceobjcurr.update_config_with_status(k, currv, 0)
-            else:
-                ifaceobjcurr.update_config_with_status(k, None, 1)
-
-    def _query_check(self, ifaceobj, ifaceobjcurr, ifaceobj_getfunc=None):
-        if self._is_bridge(ifaceobj):
-            self._query_check_bridge(ifaceobj, ifaceobjcurr)
-        else:
-            self._query_check_bridge_port(ifaceobj, ifaceobjcurr)
-
-    def _query_running_bridge_port(self, ifaceobjrunning):
-        bridgename = self.ipcmd.bridge_port_get_bridge_name(
-                                ifaceobjrunning.name)
-        if not bridgename:
-            self.logger.warn('%s: unable to determine bridgename'
-                             %ifaceobjrunning.name)
-            return
-        if self.brctlcmd.get_stp(bridgename) == 'no':
-           # This bridge does not run stp, return
-           return
-        # if userspace stp not set, return
-        if self.sysctl_get('net.bridge.bridge-stp-user-space') != '1':
-           return
-        v = self.mstpctlcmd.get_bridgeport_attr(bridgename,
-                                                ifaceobjrunning.name,
-                                                'portnetwork')
-        if v and v != 'no':
-           ifaceobjrunning.update_config('mstpctl-network', v)
-
-        # XXX: Can we really get path cost of a port ???
-        #v = self.mstpctlcmd.get_portpathcost(ifaceobjrunning.name, p)
-        #if v and v != self.get_mod_subattr('mstpctl-pathcost',
-        #                                   'default'):
-        #   ifaceobjrunning.update_config('mstpctl-network', v)
-
-        v = self.mstpctlcmd.get_bridgeport_attr(bridgename,
-                          ifaceobjrunning.name, 'portadminedge')
-        if v and v != 'no':
-           ifaceobjrunning.update_config('mstpctl-portadminedge', v)
-
-        v = self.mstpctlcmd.get_bridgeport_attr(bridgename,
-                                       ifaceobjrunning.name,'portp2p')
-        if v and v != 'auto':
-           ifaceobjrunning.update_config('mstpctl-portp2p', v)
-
-        v = self.mstpctlcmd.get_bridgeport_attr(bridgename,
-                        ifaceobjrunning.name, 'portrestrrole')
-        if v and v != 'no':
-           ifaceobjrunning.update_config('mstpctl-portrestrrole', v)
-
-        v = self.mstpctlcmd.get_bridgeport_attr(bridgename,
-                            ifaceobjrunning.name, 'restrtcn')
-        if v and v != 'no':
-           ifaceobjrunning.update_config('mstpctl-portrestrtcn', v)
-
-        v = self.mstpctlcmd.get_bridgeport_attr(bridgename,
-                            ifaceobjrunning.name, 'bpduguard')
-        if v and v != 'no':
-           ifaceobjrunning.update_config('mstpctl-bpduguard', v)
-
-        # XXX: Can we really get path cost of a port ???
-        #v = self.mstpctlcmd.get_bridgeport_attr(ifaceobjrunning.name,
-        #            p, 'treeprio')
-        #if v and v != self.get_mod_subattr('mstpctl-treeportprio',
-        #                                   'default'):
-        #    portconfig['mstpctl-treeportprio'] += ' %s=%s' %(p, v)
-
-        #v = self.mstpctlcmd.get_bridgeport_attr(ifaceobjrunning.name,
-        #               p, 'treecost')
-        #if v and v != self.get_mod_subattr('mstpctl-treeportcost',
-        #                                   'default'):
-        #    portconfig['mstpctl-treeportcost'] += ' %s=%s' %(p, v)
-
-    def _query_running_bridge(self, ifaceobjrunning):
-        if self.brctlcmd.get_stp(ifaceobjrunning.name) == 'no':
-           # This bridge does not run stp, return
-           return
-        # if userspace stp not set, return
-        if self.sysctl_get('net.bridge.bridge-stp-user-space') != '1':
-           return
-        # Check if mstp really knows about this bridge
-        if not self.mstpctlcmd.mstpbridge_exists(ifaceobjrunning.name):
-            return
-        ifaceobjrunning.update_config_dict(self._query_running_attrs(
-                                           ifaceobjrunning))
-
-    def _query_running(self, ifaceobjrunning, **extra_args):
-        if self.brctlcmd.bridge_exists(ifaceobjrunning.name):
-            self._query_running_bridge(ifaceobjrunning)
-        elif self.brctlcmd.is_bridge_port(ifaceobjrunning.name):
-            self._query_running_bridge_port(ifaceobjrunning)
-
-    _run_ops = {'pre-up' : _up,
-               'post-down' : _down,
-               'query-checkcurr' : _query_check,
-               'query-running' : _query_running}
-
-    def get_ops(self):
-        """ returns list of ops supported by this module """
-        return self._run_ops.keys()
-
-    def _init_command_handlers(self):
-        flags = self.get_flags()
-        if not self.ipcmd:
-            self.ipcmd = iproute2(**flags)
-        if not self.brctlcmd:
-            self.brctlcmd = brctl(**flags)
-        if not self.mstpctlcmd:
-            self.mstpctlcmd = mstpctlutil(**flags)
-
-    def run(self, ifaceobj, operation, query_ifaceobj=None,
-            ifaceobj_getfunc=None, **extra_args):
-        """ run mstp configuration on the interface object passed as argument
-
-        Args:
-            **ifaceobj** (object): iface object
-
-            **operation** (str): any of 'pre-up', 'post-down', 'query-checkcurr',
-                                 'query-running'
-        Kwargs:
-            **query_ifaceobj** (object): query check ifaceobject. This is only
-                valid when op is 'query-checkcurr'. It is an object same as
-                ifaceobj, but contains running attribute values and its config
-                status. The modules can use it to return queried running state
-                of interfaces. status is success if the running state is same
-                as user required state in ifaceobj. error otherwise.
-        """
-        if ifaceobj.type == ifaceType.BRIDGE_VLAN:
-           return
-        op_handler = self._run_ops.get(operation)
-        if not op_handler:
-           return
-        self._init_command_handlers()
-        if operation == 'query-checkcurr':
-            op_handler(self, ifaceobj, query_ifaceobj,
-                       ifaceobj_getfunc=ifaceobj_getfunc)
-        else:
-            op_handler(self, ifaceobj, ifaceobj_getfunc=ifaceobj_getfunc)
diff --git a/ifupdown2/addons/usercmds.py b/ifupdown2/addons/usercmds.py
deleted file mode 100644 (file)
index 72915ea..0000000
+++ /dev/null
@@ -1,97 +0,0 @@
-#!/usr/bin/python
-#
-# Copyright 2014 Cumulus Networks, Inc. All rights reserved.
-# Author: Roopa Prabhu, roopa@cumulusnetworks.com
-#
-
-import subprocess
-import ifupdownaddons
-
-class usercmds(ifupdownaddons.modulebase.moduleBase):
-    """  ifupdown2 addon module to configure user specified commands """
-
-    _modinfo = {'mhelp' : 'user commands for interfaces',
-                'attrs' : {
-                   'pre-up' :
-                        {'help' : 'run command before bringing the interface up'},
-                   'up' :
-                        {'help' : 'run command at interface bring up'},
-                   'post-up' :
-                        {'help' : 'run command after interface bring up'},
-                   'pre-down' :
-                        {'help' : 'run command before bringing the interface down'},
-                   'down' :
-                        {'help' : 'run command at interface down'},
-                   'post-down' :
-                        {'help' : 'run command after bringing interface down'}}}
-
-    def _exec_user_cmd(self, cmd):
-        """ exec's commands using subprocess Popen
-
-        special wrapper using use closefds=True and shell=True
-        for user commands
-        """
-
-        cmd_returncode = 0
-        try:
-            self.logger.info('executing %s' %cmd)
-            if self.DRYRUN:
-                return
-            ch = subprocess.Popen(cmd,
-                    stdout=subprocess.PIPE,
-                    shell=True,
-                    stderr=subprocess.STDOUT,
-                    close_fds=True)
-            cmd_returncode = ch.wait()
-            cmdout = ch.communicate()[0]
-        except Exception, e:
-            raise Exception('failed to execute cmd \'%s\' (%s)'
-                            %(cmd, str(e)))
-        if cmd_returncode != 0:
-            raise Exception(cmdout)
-        return cmdout
-
-    def _run_command(self, ifaceobj, op):
-        cmd_list = ifaceobj.get_attr_value(op)
-        if cmd_list:
-            for cmd in cmd_list:
-                self.logger.info('executing cmd \'%s\'' %cmd)
-                try:
-                    self._exec_user_cmd(cmd)
-                except Exception, e:
-                    if not self.ignore_error(str(e)):
-                        self.logger.warn('%s: %s cmd \'%s\' failed (%s)'
-                                %(ifaceobj.name, op, cmd, str(e).strip('\n')))
-                    pass
-
-    _run_ops = {'pre-up' : _run_command,
-               'pre-down' : _run_command,
-               'up' : _run_command,
-               'post-up' : _run_command,
-               'down' : _run_command,
-               'post-down' : _run_command}
-
-    def get_ops(self):
-        """ returns list of ops supported by this module """
-        return self._run_ops.keys()
-
-    def run(self, ifaceobj, operation, query_ifaceobj=None, **extra_args):
-        """ run user commands
-
-        Args:
-            **ifaceobj** (object): iface object
-
-            **operation** (str): list of ops
-
-        Kwargs:
-            **query_ifaceobj** (object): query check ifaceobject. This is only
-                valid when op is 'query-checkcurr'. It is an object same as
-                ifaceobj, but contains running attribute values and its config
-                status. The modules can use it to return queried running state
-                of interfaces. status is success if the running state is same
-                as user required state in ifaceobj. error otherwise.
-        """
-        op_handler = self._run_ops.get(operation)
-        if not op_handler:
-            return
-        op_handler(self, ifaceobj, operation)
diff --git a/ifupdown2/addons/vlan.py b/ifupdown2/addons/vlan.py
deleted file mode 100644 (file)
index c877d55..0000000
+++ /dev/null
@@ -1,237 +0,0 @@
-#!/usr/bin/python
-#
-# Copyright 2014 Cumulus Networks, Inc. All rights reserved.
-# Author: Roopa Prabhu, roopa@cumulusnetworks.com
-#
-
-from ifupdown.iface import *
-from ifupdownaddons.modulebase import moduleBase
-from ifupdownaddons.iproute2 import iproute2
-import ifupdown.rtnetlink_api as rtnetlink_api
-import logging
-import re
-
-class vlan(moduleBase):
-    """  ifupdown2 addon module to configure vlans """
-
-    _modinfo = {'mhelp' : 'vlan module configures vlan interfaces.' +
-                        'This module understands vlan interfaces with dot ' +
-                        'notations. eg swp1.100. Vlan interfaces with any ' +
-                        'other names need to have raw device and vlan id ' +
-                        'attributes',
-                'attrs' : {
-                        'vlan-raw-device' :
-                            {'help' : 'vlan raw device'},
-                        'vlan-id' :
-                            {'help' : 'vlan id'}}}
-
-
-    def __init__(self, *args, **kargs):
-        moduleBase.__init__(self, *args, **kargs)
-        self.ipcmd = None
-        self._bridge_vids_query_cache = {}
-        self._resv_vlan_range =  self._get_reserved_vlan_range()
-        self.logger.debug('%s: using reserved vlan range %s'
-                  %(self.__class__.__name__, str(self._resv_vlan_range)))
-
-    def _is_vlan_device(self, ifaceobj):
-        vlan_raw_device = ifaceobj.get_attr_value_first('vlan-raw-device')
-        if vlan_raw_device:
-            return True
-        elif '.' in ifaceobj.name:
-            return True
-        return False
-
-    def _get_vlan_id(self, ifaceobj):
-        """ Derives vlanid from iface name
-        
-        Example:
-            Returns 1 for ifname vlan0001 returns 1
-            Returns 1 for ifname vlan1
-            Returns 1 for ifname eth0.1
-
-            Returns -1 if vlan id cannot be determined
-        """
-        vid_str = ifaceobj.get_attr_value_first('vlan-id')
-        try:
-            if vid_str: return int(vid_str)
-        except:
-            return -1
-
-        if '.' in ifaceobj.name:
-            vid_str = ifaceobj.name.split('.', 1)[1]
-        elif ifaceobj.name.startswith('vlan'):
-            vid_str = ifaceobj.name[4:]
-        else:
-            return -1
-        try:
-            vid = int(vid_str)
-        except:
-            return -1
-        return vid
-
-    def _is_vlan_by_name(self, ifacename):
-        return '.' in ifacename
-
-    def _get_vlan_raw_device_from_ifacename(self, ifacename):
-        """ Returns vlan raw device from ifname
-        Example:
-            Returns eth0 for ifname eth0.100
-
-            Returns None if vlan raw device name cannot
-            be determined
-        """
-        vlist = ifacename.split('.', 1)
-        if len(vlist) == 2:
-            return vlist[0]
-        return None
-
-    def _get_vlan_raw_device(self, ifaceobj):
-        vlan_raw_device = ifaceobj.get_attr_value_first('vlan-raw-device')
-        if vlan_raw_device:
-            return vlan_raw_device
-        return self._get_vlan_raw_device_from_ifacename(ifaceobj.name)
-        
-    def get_dependent_ifacenames(self, ifaceobj, ifaceobjs_all=None):
-        if not self._is_vlan_device(ifaceobj):
-            return None
-        ifaceobj.link_kind |= ifaceLinkKind.VLAN
-        return [self._get_vlan_raw_device(ifaceobj)]
-
-    def _bridge_vid_add_del(self, ifaceobj, bridgename, vlanid,
-                            add=True):
-        """ If the lower device is a vlan aware bridge, add/del the vlanid
-        to the bridge """
-        if self.ipcmd.bridge_is_vlan_aware(bridgename):
-           if add:
-              rtnetlink_api.rtnl_api.bridge_vlan(add=True, dev=bridgename,
-                                                 vid=vlanid, master=False)
-           else:
-              rtnetlink_api.rtnl_api.bridge_vlan(add=False, dev=bridgename,
-                                                 vid=vlanid, master=False)
-
-    def _bridge_vid_check(self, ifaceobj, ifaceobjcurr, bridgename, vlanid):
-        """ If the lower device is a vlan aware bridge, check if the vlanid
-        is configured on the bridge """
-        if not self.ipcmd.bridge_is_vlan_aware(bridgename):
-            return
-        vids = self._bridge_vids_query_cache.get(bridgename)
-        if vids == None:
-           vids = self.ipcmd.bridge_port_vids_get(bridgename)
-           self._bridge_vids_query_cache[bridgename] = vids
-        if not vids or vlanid not in vids:
-            ifaceobjcurr.status = ifaceStatus.ERROR
-            ifaceobjcurr.status_str = 'bridge vid error'
-
-    def _up(self, ifaceobj):
-        vlanid = self._get_vlan_id(ifaceobj)
-        if vlanid == -1:
-            raise Exception('could not determine vlanid')
-        if self._handle_reserved_vlan(vlanid, ifaceobj.name):
-           return
-        vlanrawdevice = self._get_vlan_raw_device(ifaceobj)
-        if not vlanrawdevice:
-            raise Exception('could not determine vlan raw device')
-        if not self.PERFMODE:
-            if not self.ipcmd.link_exists(vlanrawdevice):
-                raise Exception('rawdevice %s not present' %vlanrawdevice)
-            if self.ipcmd.link_exists(ifaceobj.name):
-                self._bridge_vid_add_del(ifaceobj, vlanrawdevice, vlanid)
-                return
-        rtnetlink_api.rtnl_api.create_vlan(vlanrawdevice,
-                    ifaceobj.name, vlanid)
-        self._bridge_vid_add_del(ifaceobj, vlanrawdevice, vlanid)
-        if ifaceobj.addr_method == 'manual':
-           rtnetlink_api.rtnl_api.link_set(ifaceobj.name, "up")
-
-    def _down(self, ifaceobj):
-        vlanid = self._get_vlan_id(ifaceobj)
-        if vlanid == -1:
-            raise Exception('could not determine vlanid')
-        vlanrawdevice = self._get_vlan_raw_device(ifaceobj)
-        if not vlanrawdevice:
-            raise Exception('could not determine vlan raw device')
-        if not self.PERFMODE and not self.ipcmd.link_exists(ifaceobj.name):
-           return
-        try:
-            self.ipcmd.link_delete(ifaceobj.name)
-            self._bridge_vid_add_del(ifaceobj, vlanrawdevice, vlanid, add=False)
-        except Exception, e:
-            self.log_warn(str(e))
-
-    def _query_check(self, ifaceobj, ifaceobjcurr):
-        if not self.ipcmd.link_exists(ifaceobj.name):
-           return
-        if not '.' in ifaceobj.name:
-            # if vlan name is not in the dot format, check its running state
-            (vlanrawdev, vlanid) = self.ipcmd.get_vlandev_attrs(ifaceobj.name)
-            if vlanrawdev != ifaceobj.get_attr_value_first('vlan-raw-device'):
-                ifaceobjcurr.update_config_with_status('vlan-raw-device',
-                        vlanrawdev, 1)
-            else:
-                ifaceobjcurr.update_config_with_status('vlan-raw-device',
-                        vlanrawdev, 0)
-            if vlanid != ifaceobj.get_attr_value_first('vlan-id'):
-                ifaceobjcurr.update_config_with_status('vlan-id', vlanid, 1)
-            else:
-                ifaceobjcurr.update_config_with_status('vlan-id',
-                        vlanid, 0)
-            self._bridge_vid_check(ifaceobj, ifaceobjcurr, vlanrawdev, vlanid)
-
-    def _query_running(self, ifaceobjrunning):
-        if not self.ipcmd.link_exists(ifaceobjrunning.name):
-            return
-        if not self.ipcmd.get_vlandev_attrs(ifaceobjrunning.name):
-            return
-        # If vlan name is not in the dot format, get the
-        # vlan dev and vlan id
-        if not '.' in ifaceobjrunning.name:
-            (vlanrawdev, vlanid) = self.ipcmd.get_vlandev_attrs(ifaceobjrunning.name)
-            ifaceobjrunning.update_config_dict({(k, v) for k, v in
-                                                {'vlan-raw-device' : vlanrawdev,
-                                                 'vlan-id' : vlanid}.items()
-                                                if v})
-
-    _run_ops = {'pre-up' : _up,
-               'post-down' : _down,
-               'query-checkcurr' : _query_check,
-               'query-running' : _query_running}
-
-    def get_ops(self):
-        """ returns list of ops supported by this module """
-        return self._run_ops.keys()
-
-    def _init_command_handlers(self):
-        if not self.ipcmd:
-            self.ipcmd = iproute2(**self.get_flags())
-        
-
-    def run(self, ifaceobj, operation, query_ifaceobj=None, **extra_args):
-        """ run vlan configuration on the interface object passed as argument
-
-        Args:
-            **ifaceobj** (object): iface object
-
-            **operation** (str): any of 'pre-up', 'post-down', 'query-checkcurr',
-                                 'query-running'
-        Kwargs:
-            **query_ifaceobj** (object): query check ifaceobject. This is only
-                valid when op is 'query-checkcurr'. It is an object same as
-                ifaceobj, but contains running attribute values and its config
-                status. The modules can use it to return queried running state
-                of interfaces. status is success if the running state is same
-                as user required state in ifaceobj. error otherwise.
-        """
-        if ifaceobj.type == ifaceType.BRIDGE_VLAN:
-            return
-        op_handler = self._run_ops.get(operation)
-        if not op_handler:
-            return
-        if (operation != 'query-running' and
-                not self._is_vlan_device(ifaceobj)):
-            return
-        self._init_command_handlers()
-        if operation == 'query-checkcurr':
-            op_handler(self, ifaceobj, query_ifaceobj)
-        else:
-            op_handler(self, ifaceobj)
diff --git a/ifupdown2/addons/vrrpd.py b/ifupdown2/addons/vrrpd.py
deleted file mode 100644 (file)
index 9791141..0000000
+++ /dev/null
@@ -1,167 +0,0 @@
-#!/usr/bin/python
-#
-# Copyright 2014 Cumulus Networks, Inc. All rights reserved.
-# Author: Roopa Prabhu, roopa@cumulusnetworks.com
-#
-
-try:
-    from ipaddr import IPNetwork
-    from sets import Set
-    from ifupdown.iface import *
-    from ifupdownaddons.modulebase import moduleBase
-    from ifupdownaddons.iproute2 import iproute2
-    import os
-    import glob
-    import logging
-    import signal
-    import subprocess
-    import re
-except ImportError, e:
-    raise ImportError (str(e) + "- required module not found")
-
-class vrrpd(moduleBase):
-    """  ifupdown2 addon module to configure vrrpd attributes """
-
-    _modinfo = {'mhelp' : 'ethtool configuration module for interfaces',
-                'attrs': {
-                      'vrrp-id' :
-                            {'help' : 'vrrp instance id',
-                             'example' : ['vrrp-id 1']},
-                      'vrrp-priority' :
-                            {'help': 'set vrrp priority',
-                             'example' : ['vrrp-priority 20']},
-                      'vrrp-virtual-ip' :
-                            {'help': 'set vrrp virtual ip',
-                             'example' : ['vrrp-virtual-ip 10.0.1.254']}}}
-
-    def __init__(self, *args, **kargs):
-        moduleBase.__init__(self, *args, **kargs)
-        self.ipcmd = None
-
-    def _check_if_process_is_running(self, cmdname, cmdline):
-        targetpids = []
-        pidstr = ''
-        try:
-            pidstr = subprocess.check_output(['/bin/pidof',
-                                             '%s' %cmdname]).strip('\n')
-        except:
-            pass
-        if not pidstr:
-           return []
-
-        pids = pidstr.split()
-        if not pids:
-           return targetpids
-        for pid in pids:
-            tmpcmdline = cmdline.replace(' ', '')
-            try:
-                pcmdline = self.read_file_oneline('/proc/%s/cmdline' %pid)
-                pcmdline = re.sub(r'\\(.)', r'\1', pcmdline)
-                self.logger.info('(%s)' %(pcmdline))
-                self.logger.info('(%s)' %(tmpcmdline))
-                self.logger.info('(%d) (%d)' %(len(pcmdline), len(tmpcmdline)))
-                if pcmdline and pcmdline == tmpcmdline:
-                   targetpids.append(pid)
-            except:
-                pass
-        return targetpids
-            
-    def _up(self, ifaceobj):
-        """ up vrrpd -n -D -i $IFACE -v 1 -p 20 10.0.1.254
-            up ifplugd -i $IFACE -b -f -u0 -d1 -I -p -q """
-
-        if (not self.DRYRUN and
-            not os.path.exists('/sys/class/net/%s' %ifaceobj.name)):
-            return
-
-        cmd = ''
-        attrval = ifaceobj.get_attr_value_first('vrrp-id')
-        if attrval:
-            cmd += ' -v %s' %attrval
-        else:
-            return
-        attrval = ifaceobj.get_attr_value_first('vrrp-priority')
-        if attrval:
-            cmd += ' -p %s' %attrval
-        else:
-            self.logger.warn('%s: incomplete vrrp parameters ' %ifaceobj.name,
-                    '(priority not found)')
-        attrval = ifaceobj.get_attr_value_first('vrrp-virtual-ip')
-        if attrval:
-            cmd += ' %s' %attrval
-        else:
-            self.logger.warn('%s: incomplete vrrp arguments ' %ifaceobj.name,
-                    '(virtual ip not found)')
-            return
-        cmd = '/usr/sbin/vrrpd -n -D -i %s %s' %(ifaceobj.name, cmd)
-        self.exec_command(cmd)
-
-        cmd = '/usr/sbin/ifplugd -i %s -b -f -u0 -d1 -I -p -q' %ifaceobj.name
-        if self._check_if_process_is_running('/usr/sbin/ifplugd', cmd):
-           self.logger.info('%s: ifplugd already running' %ifaceobj.name)
-           return
-        self.exec_command(cmd)
-
-    def _kill_pid_from_file(self, pidfilename):
-        if os.path.exists(pidfilename):
-            pid = self.read_file_oneline(pidfilename)
-            if os.path.exists('/proc/%s' %pid):
-               os.kill(int(pid), signal.SIGTERM)
-
-    def _down(self, ifaceobj):
-        """ down ifplugd -k -i $IFACE
-             down kill $(cat /var/run/vrrpd_$IFACE_*.pid) """
-        attrval = ifaceobj.get_attr_value_first('vrrp-id')
-        if not attrval:
-            return
-        try:
-            self.exec_command('/usr/sbin/ifplugd -k -i %s' %ifaceobj.name)
-        except Exception, e:
-            self.logger.debug('%s: ifplugd down error (%s)'
-                              %(ifaceobj.name, str(e)))
-            pass
-
-        for pidfile in glob.glob('/var/run/vrrpd_%s_*.pid' %ifaceobj.name):
-            try:
-                self._kill_pid_from_file(pidfile)
-            except Exception, e:
-                self.logger.debug('%s: vrrpd down error (%s)'
-                                  %(ifaceobj.name, str(e)))
-                pass
-
-    def _query_check(self, ifaceobj, ifaceobjcurr):
-        # XXX
-        return
-
-
-    _run_ops = {'post-up' : _up,
-                'pre-down' : _down}
-
-    def get_ops(self):
-        """ returns list of ops supported by this module """
-        return self._run_ops.keys()
-
-    def run(self, ifaceobj, operation, query_ifaceobj=None, **extra_args):
-        """ run ethtool configuration on the interface object passed as
-            argument
-
-        Args:
-            **ifaceobj** (object): iface object
-
-            **operation** (str): any of 'post-up', 'query-checkcurr',
-                'query-running'
-        Kwargs:
-            **query_ifaceobj** (object): query check ifaceobject. This is only
-                valid when op is 'query-checkcurr'. It is an object same as
-                ifaceobj, but contains running attribute values and its config
-                status. The modules can use it to return queried running state
-                of interfaces. status is success if the running state is same
-                as user required state in ifaceobj. error otherwise.
-        """
-        op_handler = self._run_ops.get(operation)
-        if not op_handler:
-            return
-        if operation == 'query-checkcurr':
-            op_handler(self, ifaceobj, query_ifaceobj)
-        else:
-            op_handler(self, ifaceobj)
diff --git a/ifupdown2/addons/vxlan.py b/ifupdown2/addons/vxlan.py
deleted file mode 100644 (file)
index a367e99..0000000
+++ /dev/null
@@ -1,167 +0,0 @@
-#!/usr/bin/python
-
-from ifupdown.iface import *
-from ifupdownaddons.modulebase import moduleBase
-from ifupdownaddons.iproute2 import iproute2
-import ifupdown.rtnetlink_api as rtnetlink_api
-import logging
-from sets import Set
-
-class vxlan(moduleBase):
-    _modinfo = {'mhelp' : 'vxlan module configures vxlan interfaces.',
-                'attrs' : {
-                        'vxlan-id' :
-                            {'help' : 'vxlan id',
-                             'required' : True,
-                             'example': ['vxlan-id 100']},
-                        'vxlan-local-tunnelip' :
-                            {'help' : 'vxlan local tunnel ip',
-                             'example': ['vxlan-local-tunnelip 172.16.20.103']},
-                        'vxlan-svcnodeip' :
-                            {'help' : 'vxlan id',
-                             'example': ['vxlan-svcnodeip 172.16.22.125']},
-                        'vxlan-remoteip' :
-                            {'help' : 'vxlan remote ip',
-                             'example': ['vxlan-remoteip 172.16.22.127']},
-                        'vxlan-learning' :
-                            {'help' : 'vxlan learning on/off',
-                             'example': ['vxlan-learning off'],
-                             'default': 'on'},
-                }}
-
-    def __init__(self, *args, **kargs):
-        moduleBase.__init__(self, *args, **kargs)
-        self.ipcmd = None
-
-    def get_dependent_ifacenames(self, ifaceobj, ifaceobjs_all=None):
-        if not self._is_vxlan_device(ifaceobj):
-            return None
-        ifaceobj.link_kind |= ifaceLinkKind.VXLAN
-        return None
-
-    def _is_vxlan_device(self, ifaceobj):
-        if ifaceobj.get_attr_value_first('vxlan-id'):
-            return True
-        return False
-
-    def _up(self, ifaceobj):
-        vxlanid = ifaceobj.get_attr_value_first('vxlan-id')
-        if vxlanid:
-            self.ipcmd.link_create_vxlan(ifaceobj.name, vxlanid,
-            localtunnelip=ifaceobj.get_attr_value_first('vxlan-local-tunnelip'),
-            svcnodeips=ifaceobj.get_attr_value('vxlan-svcnodeip'),
-            remoteips=ifaceobj.get_attr_value('vxlan-remoteip'),
-            learning=ifaceobj.get_attr_value_first('vxlan-learning'),
-            ageing=ifaceobj.get_attr_value_first('vxlan-ageing'))
-            if ifaceobj.addr_method == 'manual':
-               rtnetlink_api.rtnl_api.link_set(ifaceobj.name, "up")
-
-    def _down(self, ifaceobj):
-        try:
-            self.ipcmd.link_delete(ifaceobj.name)
-        except Exception, e:
-            self.log_warn(str(e))
-
-    def _query_check_n_update(self, ifaceobjcurr, attrname, attrval,
-                              running_attrval):
-        if running_attrval and attrval == running_attrval:
-           ifaceobjcurr.update_config_with_status(attrname, attrval, 0)
-        else:
-           ifaceobjcurr.update_config_with_status(attrname, running_attrval, 1)
-
-    def _query_check_n_update_addresses(self, ifaceobjcurr, attrname,
-                                        addresses, running_addresses):
-        if addresses:
-            for a in addresses: 
-                if a in running_addresses:
-                    ifaceobjcurr.update_config_with_status(attrname, a, 0)
-                else:
-                    ifaceobjcurr.update_config_with_status(attrname, a, 1)
-            running_addresses = Set(running_addresses).difference(
-                                                    Set(addresses))
-        [ifaceobjcurr.update_config_with_status(attrname, a, 1)
-                    for a in running_addresses]
-
-    def _query_check(self, ifaceobj, ifaceobjcurr):
-        if not self.ipcmd.link_exists(ifaceobj.name):
-           return
-        # Update vxlan object
-        vxlanattrs = self.ipcmd.get_vxlandev_attrs(ifaceobj.name)
-        if not vxlanattrs:
-            ifaceobjcurr.check_n_update_config_with_status_many(ifaceobj,
-                    self.get_mod_attrs(), -1)
-            return
-        self._query_check_n_update(ifaceobjcurr, 'vxlan-id',
-                       ifaceobj.get_attr_value_first('vxlan-id'), 
-                       vxlanattrs.get('vxlanid'))
-
-        self._query_check_n_update(ifaceobjcurr, 'vxlan-local-tunnelip',
-                       ifaceobj.get_attr_value_first('vxlan-local-tunnelip'), 
-                       vxlanattrs.get('local'))
-
-        self._query_check_n_update_addresses(ifaceobjcurr, 'vxlan-svcnodeip',
-                       ifaceobj.get_attr_value('vxlan-svcnodeip'), 
-                       vxlanattrs.get('svcnode', []))
-
-        self._query_check_n_update_addresses(ifaceobjcurr, 'vxlan-remoteip',
-                       ifaceobj.get_attr_value('vxlan-remoteip'), 
-                       vxlanattrs.get('remote', []))
-
-        learning = ifaceobj.get_attr_value_first('vxlan-learning')
-        if not learning:
-            learning = 'on'
-        running_learning = vxlanattrs.get('learning')
-        if learning == running_learning:
-           ifaceobjcurr.update_config_with_status('vxlan-learning',
-                                                  running_learning, 0)
-        else:
-           ifaceobjcurr.update_config_with_status('vxlan-learning',
-                                                  running_learning, 1)
-
-    def _query_running(self, ifaceobjrunning):
-        vxlanattrs = self.ipcmd.get_vxlandev_attrs(ifaceobjrunning.name)
-        if not vxlanattrs:
-            return
-        attrval = vxlanattrs.get('vxlanid')
-        if attrval:
-            ifaceobjrunning.update_config('vxlan-id', vxlanattrs.get('vxlanid'))
-        attrval = vxlanattrs.get('local')
-        if attrval:
-            ifaceobjrunning.update_config('vxlan-local-tunnelip', attrval)
-        attrval = vxlanattrs.get('svcnode')
-        if attrval:
-            [ifaceobjrunning.update_config('vxlan-svcnode', a)
-                        for a in attrval]
-        attrval = vxlanattrs.get('remote')
-        if attrval:
-            [ifaceobjrunning.update_config('vxlan-remoteip', a)
-                        for a in attrval]
-        attrval = vxlanattrs.get('learning')
-        if attrval and attrval == 'on':
-            ifaceobjrunning.update_config('vxlan-learning', 'on')
-
-
-    _run_ops = {'pre-up' : _up,
-               'post-down' : _down,
-               'query-checkcurr' : _query_check,
-               'query-running' : _query_running}
-
-    def get_ops(self):
-        return self._run_ops.keys()
-
-    def _init_command_handlers(self):
-        if not self.ipcmd:
-            self.ipcmd = iproute2(**self.get_flags())
-
-    def run(self, ifaceobj, operation, query_ifaceobj=None, **extra_args):
-        op_handler = self._run_ops.get(operation)
-        if not op_handler:
-            return
-        if (operation != 'query-running' and
-                not self._is_vxlan_device(ifaceobj)):
-            return
-        self._init_command_handlers()
-        if operation == 'query-checkcurr':
-            op_handler(self, ifaceobj, query_ifaceobj)
-        else:
-            op_handler(self, ifaceobj)
diff --git a/ifupdown2/build.sh b/ifupdown2/build.sh
deleted file mode 100755 (executable)
index 9fd4f2b..0000000
+++ /dev/null
@@ -1,8 +0,0 @@
-#!/bin/bash
-
-TOPDIR=.
-
-${TOPDIR}/scripts/genmanpages.sh ${TOPDIR}/man.rst ${TOPDIR}/man
-
-python setup.py --command-packages=stdeb.command sdist_dsc bdist_deb
-
diff --git a/ifupdown2/completion/ifup b/ifupdown2/completion/ifup
deleted file mode 100644 (file)
index 0be547f..0000000
+++ /dev/null
@@ -1,9 +0,0 @@
-
-_python_argcomplete() {
-    local IFS='\v'
-    COMPREPLY=( $(IFS="$IFS" COMP_LINE="$COMP_LINE" COMP_POINT="$COMP_POINT"                   _ARGCOMPLETE_COMP_WORDBREAKS="$COMP_WORDBREAKS"                   _ARGCOMPLETE=1  "$1" 8>&1 9>&2 1>/dev/null 2>/dev/null) )
-    if [[ $? != 0 ]]; then
-        unset COMPREPLY
-    fi
-}
-complete -F _python_argcomplete ifup ifdown ifquery ifreload
diff --git a/ifupdown2/config/addons.conf b/ifupdown2/config/addons.conf
deleted file mode 100644 (file)
index a96b75e..0000000
+++ /dev/null
@@ -1,29 +0,0 @@
-pre-up,ifenslave
-pre-up,clagd
-pre-up,vlan
-pre-up,vxlan
-pre-up,usercmds
-pre-up,bridge
-pre-up,bridgevlan
-pre-up,mstpctl
-up,dhcp
-up,address
-up,addressvirtual
-up,usercmds
-post-up,ethtool
-post-up,usercmds
-post-up,clagd
-pre-down,usercmds
-pre-down,ethtool
-down,dhcp
-down,addressvirtual
-down,address
-down,usercmds
-post-down,clagd
-post-down,mstpctl
-post-down,bridgevlan
-post-down,bridge
-post-down,vxlan
-post-down,vlan
-post-down,ifenslave
-post-down,usercmds
diff --git a/ifupdown2/config/ifupdown2.conf b/ifupdown2/config/ifupdown2.conf
deleted file mode 100644 (file)
index 82c618e..0000000
+++ /dev/null
@@ -1,44 +0,0 @@
-#
-# ifupdown2 configuration file
-#
-# This file contains default settings for ifupdown
-#
-
-# default template engine (only mako is currently supported)
-template_engine=mako
-
-# default template lookup path during template rendering
-template_lookuppath=/etc/network/ifupdown2/templates
-
-# Support /etc/network/if-*/ scripts
-addon_scripts_support=0
-
-# By default ifupdown2 only supports a single vlan filtering bridge
-# on the system. Set this flag to 1 to support multiple vlan
-# filtering bridges
-multiple_vlan_aware_bridge_support=0
-
-# ifquery check status strings.
-# By default `ifquery --check` prints the check and
-# cross marks against interface attributes.
-# Use the below strings to modify the default behaviour.
-#
-ifquery_check_success_str=[pass]
-ifquery_check_error_str=[fail]
-ifquery_check_unknown_str=
-#
-
-# This attribute controls iface/vlan range expansions
-# in ifquery default output.
-ifquery_ifacename_expand_range=0
-
-# Let link master (bridges, bonds) own the link state of slaves
-link_master_slave=1
-
-# Delay admin state change till the end
-delay_admin_state_change=0
-
-# ifreload by default downs: 'all interfaces for which config changed' +
-# 'interfaces that were deleted'. With the below variable set to '0'
-# ifreload will only down 'interfaces that were deleted'
-ifreload_down_changed=0
diff --git a/ifupdown2/config/networking b/ifupdown2/config/networking
deleted file mode 100644 (file)
index cc3d3ef..0000000
+++ /dev/null
@@ -1,23 +0,0 @@
-#
-#
-# Parameters for the /etc/init.d/networking script
-#
-#
-
-# Change the below to yes if you want verbose logging to be enabled
-VERBOSE="no"
-
-# Change the below to yes if you want debug logging to be enabled
-DEBUG="no"
-
-# Change the below to yes if you want logging to go to syslog
-SYSLOG="no"
-
-# Exclude interfaces
-EXCLUDE_INTERFACES=
-
-# Set to 'yes' if you want to skip ifdown during system reboot
-# and shutdown. This is of interest in large scale interface
-# deployments where you dont want to wait for interface
-# deconfiguration to speed up shutdown/reboot
-SKIP_DOWN_AT_SYSRESET="yes"
diff --git a/ifupdown2/debian/copyright b/ifupdown2/debian/copyright
deleted file mode 100644 (file)
index f560d80..0000000
+++ /dev/null
@@ -1,30 +0,0 @@
-Format: http://www.debian.org/doc/packaging-manuals/copyright-format/1.0/
-Upstream-Name: ifupdown2
-Source: http://www.cumulusnetworks.com
-
-Files: *
-Copyright: 2013 Cumulus Networks
-License: GPL-2
-
-Files: debian/*
-Copyright: 2013 Cumulus Networks
-License: GPL-2
- This package 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; version 2 of the License
- .
- This package 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/>
- .
- On Debian systems, the complete text of the GNU General
- Public License version 2 can be found in "/usr/share/common-licenses/GPL-2".
-
-# Please also look if there are files or directories which have a
-# different copyright/license attached and list them here.
-# Please avoid to pick license terms that are more restrictive than the
-# packaged work, as it may make Debian's contributions unacceptable upstream.
diff --git a/ifupdown2/debian/python-ifupdown2.postinst b/ifupdown2/debian/python-ifupdown2.postinst
deleted file mode 100644 (file)
index cf61919..0000000
+++ /dev/null
@@ -1,114 +0,0 @@
-#!/bin/sh
-# postinst script for ifupdown2
-#
-# see: dh_installdeb(1)
-
-set -e
-
-# summary of how this script can be called:
-#        * <postinst> `configure' <most-recently-configured-version>
-#        * <old-postinst> `abort-upgrade' <new version>
-#        * <conflictor's-postinst> `abort-remove' `in-favour' <package>
-#          <new-version>
-#        * <postinst> `abort-remove'
-#        * <deconfigured's-postinst> `abort-deconfigure' `in-favour'
-#          <failed-install-package> <version> `removing'
-#          <conflicting-package> <version>
-# for details, see http://www.debian.org/doc/debian-policy/ or
-# the debian-policy package
-
-process_udev()
-{
-    # override default udev bridge and hotplug rules because they interfere with
-    # networking init script
-    udev_user_rulesdir=/etc/udev/rules.d/
-    udev_sys_rulesdir=/lib/udev/rules.d/
-    if [ -e $udev_user_rulesdir ]; then
-        udev_ifupdown2_overrides="80-networking.rules
-        60-bridge-network-interface.rules"
-        for u in ${udev_ifupdown2_overrides}
-        do
-            if [ -e ${udev_sys_rulesdir}/$u -a ! -e ${udev_user_rulesdir}/$u ]; then
-                (cd ${udev_user_rulesdir} && ln -sf /dev/null $u)
-            fi
-        done
-    fi
-}
-
-MYNAME="${0##*/}"
-
-report() { echo "${MYNAME}: $*" ; }
-report_warn() { report "Warning: $*" >&2 ; }
-report_err() { report "Error: $*" >&2 ; }
-
-case "$1" in
-    configure)
-        # Create /etc/network/run
-        [ -d /run/network ] || mkdir -p /run/network
-
-        # for backward compatibility
-        if [ ! -f /etc/network/run ]; then
-            ln -sf /run/network /etc/network/run
-        fi
-
-        ln -sf /usr/share/python-ifupdown2/generate_interfaces.py \
-            /usr/share/doc/python-ifupdown2/examples/generate_interfaces.py
-
-        [ -d /etc/network/if-pre-up.d ] || mkdir -p /etc/network/if-pre-up.d
-        [ -d /etc/network/if-up.d ] || mkdir -p /etc/network/if-up.d
-        [ -d /etc/network/if-post-up.d ] || mkdir -p /etc/network/if-post-up.d
-
-        [ -d /etc/network/if-pre-down.d ] || mkdir -p /etc/network/if-pre-down.d
-        [ -d /etc/network/if-down.d ] || mkdir -p /etc/network/if-down.d
-        [ -d /etc/network/if-post-down.d ] || mkdir -p /etc/network/if-post-down.d
-
-
-        # Generic stuff done on all configurations
-        if [ -f /etc/network/interfaces ] ; then
-            # TODO: This should be handled with debconf and the script
-            # could introduce the line there directly
-            if ! grep -q "^[[:space:]]*iface[[:space:]]\+lo0\?[[:space:]]\+inet[[:space:]]\+loopback\>" /etc/network/interfaces ; then
-                report_warn "No 'iface lo' definition found in /etc/network/interfaces"
-            fi
-
-            if ! grep -q "^[[:space:]]*\(allow-\|\)auto[[:space:]]\+\(.*[[:space:]]\+\|\)lo0\?\([[:space:]]\+\|$\)" /etc/network/interfaces ; then
-                report_warn "No 'auto lo' statement found in /etc/network/interfaces"
-            fi
-        else  # ! -f /etc/network/interfaces
-            if [ -z "$2" ]; then
-                echo "Creating /etc/network/interfaces."
-                echo "# interfaces(5) file used by ifup(8) and ifdown(8)" > /etc/network/interfaces
-                echo "auto lo" >> /etc/network/interfaces
-                    echo "iface lo inet loopback" >> /etc/network/interfaces
-            else
-                    report_warn "/etc/network/interfaces does not exist"
-            fi
-        fi
-
-        [ -e /sbin/ifup ] || ln -sf /sbin/ifupdown /sbin/ifup
-        [ -e /sbin/ifdown ] || ln -sf /sbin/ifupdown /sbin/ifdown
-        [ -e /sbin/ifquery ] || ln -sf /sbin/ifupdown /sbin/ifquery
-        [ -e /sbin/ifreload ] || ln -sf /sbin/ifupdown /sbin/ifreload
-
-        (cd /usr/share/man/man8/ && ln -sf /usr/share/man/man8/ifup.8.gz ifdown.8.gz)
-
-        mkdir -p /etc/network/interfaces.d/
-        process_udev
-        update-rc.d networking start 40 S . start 35 0 6 . >/dev/null
-        ;;
-
-    abort-upgrade|abort-remove|abort-deconfigure)
-        ;;
-
-    *)
-        echo "postinst called with unknown argument \`$1'" >&2
-        exit 1
-        ;;
-esac
-
-# dh_installdeb will replace this with shell code automatically
-# generated by other debhelper scripts.
-
-#DEBHELPER#
-
-exit 0
diff --git a/ifupdown2/debian/python-ifupdown2.postrm b/ifupdown2/debian/python-ifupdown2.postrm
deleted file mode 100644 (file)
index fe68eb4..0000000
+++ /dev/null
@@ -1,71 +0,0 @@
-#!/bin/sh
-# postrm script for ifupdown2
-#
-# see: dh_installdeb(1)
-
-set -e
-
-# summary of how this script can be called:
-#        * <postrm> `remove'
-#        * <postrm> `purge'
-#        * <old-postrm> `upgrade' <new-version>
-#        * <new-postrm> `failed-upgrade' <old-version>
-#        * <new-postrm> `abort-install'
-#        * <new-postrm> `abort-install' <old-version>
-#        * <new-postrm> `abort-upgrade' <old-version>
-#        * <disappearer's-postrm> `disappear' <overwriter>
-#          <overwriter-version>
-# for details, see http://www.debian.org/doc/debian-policy/ or
-# the debian-policy package
-
-process_udev()
-{
-    udevlink=$(readlink /etc/udev/rules.d/80-networking.rules 2>/dev/null || true)
-    [ -n "$udevlink" -a "$udevlink" == "/dev/null" ] && rm -f /etc/udev/rules.d/80-networking.rules
-    udevlink=$(readlink /etc/udev/rules.d/60-bridge-network-interface.rules 2>/dev/null || true)
-    [ -n "$udevlink" -a "$udevlink" == "/dev/null" ] && rm -f /etc/udev/rules.d/60-bridge-network-interface.rules
-}
-
-postrm_remove()
-{
-       rm -f /sbin/ifup /sbin/ifdown /sbin/ifquery
-    process_udev
-       update-rc.d networking remove >/dev/null
-}
-
-# Note: We don't remove /etc/network/interfaces
-postrm_purge()
-{
-       rm -f /var/tmp/network/ifstatenew
-       if [ -L /etc/network/run ] ; then
-               rm -f /etc/network/run
-       elif [ -d /etc/network/run ] ; then
-               rmdir --ignore-fail-on-non-empty /etc/network/run
-       fi
-}
-
-case "$1" in
-       purge)
-               postrm_purge
-       ;;
-
-       remove)
-               postrm_remove
-       ;;
-
-
-       upgrade|disappear|failed-upgrade|abort-install|abort-upgrade)
-       ;;
-
-       *)
-               echo "postrm called with unknown argument \`$1'" >&2
-               exit 1
-       ;;
-esac
-
-# dh_installdeb will replace this with shell code automatically
-# generated by other debhelper scripts.
-
-#DEBHELPER#
-
-exit 0
diff --git a/ifupdown2/debian/python-ifupdown2.preinst b/ifupdown2/debian/python-ifupdown2.preinst
deleted file mode 100755 (executable)
index 3fcaed1..0000000
+++ /dev/null
@@ -1,56 +0,0 @@
-#!/bin/sh
-# preinst script for newpkg
-#
-# see: dh_installdeb(1)
-
-set -e
-
-# summary of how this script can be called:
-#        * <new-preinst> `install'
-#        * <new-preinst> `install' <old-version>
-#        * <new-preinst> `upgrade' <old-version>
-#        * <old-preinst> `abort-upgrade' <new-version>
-# for details, see http://www.debian.org/doc/debian-policy/ or
-# the debian-policy package
-
-preinst_upgrade()
-{
-       local oldver="$1"
-       local udev_user_rulesdir="/etc/udev/rules.d"
-
-       # we have to fixup the filesystem here as previous packages of
-       # ifupdown2 introduced a bug in the postrm script that require
-       # these files to exist, otherwise the postrm script will always
-       # fail.
-       local badver="0.1-cl2.5+2"
-       if dpkg --compare-versions "${oldver}" "lt" "${badver}"; then
-               local files="${udev_user_rulesdir}/80-networking.rules
-                       ${udev_user_rulesdir}/60-bridge-network-interface.rules"
-               for f in ${files}; do
-                       echo "touching udev rule: ${f}"
-                       test ! -e "${f}" && ln -s /dev/null "${f}" || \
-                               /bin/echo -e "\tudev rule exists leaving"
-               done
-       fi
-}
-
-case "$1" in
-       install|upgrade)
-               preinst_upgrade "$2"
-       ;;
-
-       abort-upgrade)
-       ;;
-
-       *)
-               echo "preinst called with unknown argument \`$1'" >&2
-               exit 1
-       ;;
-esac
-
-# dh_installdeb will replace this with shell code automatically
-# generated by other debhelper scripts.
-
-#DEBHELPER#
-
-exit 0
diff --git a/ifupdown2/docs/Makefile b/ifupdown2/docs/Makefile
deleted file mode 100644 (file)
index 9b5efd7..0000000
+++ /dev/null
@@ -1,153 +0,0 @@
-# Makefile for Sphinx documentation
-#
-
-# You can set these variables from the command line.
-SPHINXOPTS    =
-SPHINXBUILD   = sphinx-build
-PAPER         =
-BUILDDIR      = build
-
-# Internal variables.
-PAPEROPT_a4     = -D latex_paper_size=a4
-PAPEROPT_letter = -D latex_paper_size=letter
-ALLSPHINXOPTS   = -d $(BUILDDIR)/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) source
-# the i18n builder cannot share the environment and doctrees with the others
-I18NSPHINXOPTS  = $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) source
-
-.PHONY: help clean html dirhtml singlehtml pickle json htmlhelp qthelp devhelp epub latex latexpdf text man changes linkcheck doctest gettext
-
-help:
-       @echo "Please use \`make <target>' where <target> is one of"
-       @echo "  html       to make standalone HTML files"
-       @echo "  dirhtml    to make HTML files named index.html in directories"
-       @echo "  singlehtml to make a single large HTML file"
-       @echo "  pickle     to make pickle files"
-       @echo "  json       to make JSON files"
-       @echo "  htmlhelp   to make HTML files and a HTML help project"
-       @echo "  qthelp     to make HTML files and a qthelp project"
-       @echo "  devhelp    to make HTML files and a Devhelp project"
-       @echo "  epub       to make an epub"
-       @echo "  latex      to make LaTeX files, you can set PAPER=a4 or PAPER=letter"
-       @echo "  latexpdf   to make LaTeX files and run them through pdflatex"
-       @echo "  text       to make text files"
-       @echo "  man        to make manual pages"
-       @echo "  texinfo    to make Texinfo files"
-       @echo "  info       to make Texinfo files and run them through makeinfo"
-       @echo "  gettext    to make PO message catalogs"
-       @echo "  changes    to make an overview of all changed/added/deprecated items"
-       @echo "  linkcheck  to check all external links for integrity"
-       @echo "  doctest    to run all doctests embedded in the documentation (if enabled)"
-
-clean:
-       -rm -rf $(BUILDDIR)/*
-
-html:
-       $(SPHINXBUILD) -b html $(ALLSPHINXOPTS) $(BUILDDIR)/html
-       @echo
-       @echo "Build finished. The HTML pages are in $(BUILDDIR)/html."
-
-dirhtml:
-       $(SPHINXBUILD) -b dirhtml $(ALLSPHINXOPTS) $(BUILDDIR)/dirhtml
-       @echo
-       @echo "Build finished. The HTML pages are in $(BUILDDIR)/dirhtml."
-
-singlehtml:
-       $(SPHINXBUILD) -b singlehtml $(ALLSPHINXOPTS) $(BUILDDIR)/singlehtml
-       @echo
-       @echo "Build finished. The HTML page is in $(BUILDDIR)/singlehtml."
-
-pickle:
-       $(SPHINXBUILD) -b pickle $(ALLSPHINXOPTS) $(BUILDDIR)/pickle
-       @echo
-       @echo "Build finished; now you can process the pickle files."
-
-json:
-       $(SPHINXBUILD) -b json $(ALLSPHINXOPTS) $(BUILDDIR)/json
-       @echo
-       @echo "Build finished; now you can process the JSON files."
-
-htmlhelp:
-       $(SPHINXBUILD) -b htmlhelp $(ALLSPHINXOPTS) $(BUILDDIR)/htmlhelp
-       @echo
-       @echo "Build finished; now you can run HTML Help Workshop with the" \
-             ".hhp project file in $(BUILDDIR)/htmlhelp."
-
-qthelp:
-       $(SPHINXBUILD) -b qthelp $(ALLSPHINXOPTS) $(BUILDDIR)/qthelp
-       @echo
-       @echo "Build finished; now you can run "qcollectiongenerator" with the" \
-             ".qhcp project file in $(BUILDDIR)/qthelp, like this:"
-       @echo "# qcollectiongenerator $(BUILDDIR)/qthelp/ifupdown2.qhcp"
-       @echo "To view the help file:"
-       @echo "# assistant -collectionFile $(BUILDDIR)/qthelp/ifupdown2.qhc"
-
-devhelp:
-       $(SPHINXBUILD) -b devhelp $(ALLSPHINXOPTS) $(BUILDDIR)/devhelp
-       @echo
-       @echo "Build finished."
-       @echo "To view the help file:"
-       @echo "# mkdir -p $$HOME/.local/share/devhelp/ifupdown2"
-       @echo "# ln -s $(BUILDDIR)/devhelp $$HOME/.local/share/devhelp/ifupdown2"
-       @echo "# devhelp"
-
-epub:
-       $(SPHINXBUILD) -b epub $(ALLSPHINXOPTS) $(BUILDDIR)/epub
-       @echo
-       @echo "Build finished. The epub file is in $(BUILDDIR)/epub."
-
-latex:
-       $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex
-       @echo
-       @echo "Build finished; the LaTeX files are in $(BUILDDIR)/latex."
-       @echo "Run \`make' in that directory to run these through (pdf)latex" \
-             "(use \`make latexpdf' here to do that automatically)."
-
-latexpdf:
-       $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex
-       @echo "Running LaTeX files through pdflatex..."
-       $(MAKE) -C $(BUILDDIR)/latex all-pdf
-       @echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex."
-
-text:
-       $(SPHINXBUILD) -b text $(ALLSPHINXOPTS) $(BUILDDIR)/text
-       @echo
-       @echo "Build finished. The text files are in $(BUILDDIR)/text."
-
-man:
-       $(SPHINXBUILD) -b man $(ALLSPHINXOPTS) $(BUILDDIR)/man
-       @echo
-       @echo "Build finished. The manual pages are in $(BUILDDIR)/man."
-
-texinfo:
-       $(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo
-       @echo
-       @echo "Build finished. The Texinfo files are in $(BUILDDIR)/texinfo."
-       @echo "Run \`make' in that directory to run these through makeinfo" \
-             "(use \`make info' here to do that automatically)."
-
-info:
-       $(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo
-       @echo "Running Texinfo files through makeinfo..."
-       make -C $(BUILDDIR)/texinfo info
-       @echo "makeinfo finished; the Info files are in $(BUILDDIR)/texinfo."
-
-gettext:
-       $(SPHINXBUILD) -b gettext $(I18NSPHINXOPTS) $(BUILDDIR)/locale
-       @echo
-       @echo "Build finished. The message catalogs are in $(BUILDDIR)/locale."
-
-changes:
-       $(SPHINXBUILD) -b changes $(ALLSPHINXOPTS) $(BUILDDIR)/changes
-       @echo
-       @echo "The overview file is in $(BUILDDIR)/changes."
-
-linkcheck:
-       $(SPHINXBUILD) -b linkcheck $(ALLSPHINXOPTS) $(BUILDDIR)/linkcheck
-       @echo
-       @echo "Link check complete; look for any errors in the above output " \
-             "or in $(BUILDDIR)/linkcheck/output.txt."
-
-doctest:
-       $(SPHINXBUILD) -b doctest $(ALLSPHINXOPTS) $(BUILDDIR)/doctest
-       @echo "Testing of doctests in the sources finished, look at the " \
-             "results in $(BUILDDIR)/doctest/output.txt."
diff --git a/ifupdown2/docs/examples/generate_interfaces.py b/ifupdown2/docs/examples/generate_interfaces.py
deleted file mode 100755 (executable)
index bfb2d88..0000000
+++ /dev/null
@@ -1,150 +0,0 @@
-#!/usr/bin/python
-
-import argparse
-import sys
-import subprocess
-
-""" This script prints to stdout /etc/network/interfaces entries for
-    requested interfaces.
-
-    Currently it supports generation of interfaces(5) section for all
-    swp interfaces on the system. And also an interface section 
-    for a bridge with all swp ports.
-
-    Example use of this script:
-
-    generate the swp_defaults file:
-    (bkup existing /etc/network/interfaces.d/swp_defaults file if one exists)
-
-    #generate_interfaces.py -s > /etc/network/interfaces.d/swp_defaults
-
-    User -m option if you want the new swp_defaults to be auto merged
-    with the contents from the old file, use -m option
-
-    #generate_interfaces.py -s -m /etc/network/interfaces.d/swp_defaults > /etc/network/interfaces.d/swp_defaults.new
-
-    Include the swp_defaults file in /etc/network/interfaces file
-    (if not already there) using the source command as shown below:
-
-    source /etc/network/interfaces.d/swp_defaults
-
-"""
-
-def get_swp_interfaces():
-    porttab_path = '/var/lib/cumulus/porttab'
-    ports = []
-
-    ptfile = open(porttab_path, 'r')
-    for line in ptfile.readlines():
-        line = line.strip()
-        if '#' in line:
-            continue
-        try:
-            ports.append(line.split()[0])
-        except ValueError:
-            continue
-    return ports
-
-def print_swp_defaults_header():
-    print '''
-# ** This file is autogenerated by /usr/share/doc/python-ifupdown2/generate_interfaces.py **
-#
-# This is /etc/network/interfaces section for all available swp
-# ports on the system.
-#
-# To include this file in the main /etc/network/interfaces file,
-# copy this file under /etc/network/interfaces.d/ and use the
-# source line in the /etc/network/interfaces file.
-#
-# example entry in /etc/network/interfaces:
-#   source /etc/network/interfaces.d/<filename>
-#
-# See manpage interfaces(5) for details.
-'''
-
-def print_bridge_untagged_defaults_header():
-    print '''
-# ** This file is autogenerated by /usr/share/doc/python-ifupdown2/generate_interfaces.py **
-#
-# This is /etc/network/interfaces section for a bridge device with all swp
-# ports in the system.
-#
-# To include this file in the main /etc/network/interfaces file,
-# copy this file under /etc/network/interfaces.d/ and use the
-# source line in the /etc/network/interfaces file as shown below.
-# details.
-#
-# example entry in /etc/network/interfaces:
-#   source /etc/network/interfaces.d/filename
-#
-# See manpage interfaces(5) for details
-'''
-
-def interfaces_print_swp_default(swp_intf):
-    outbuf = None
-    if args.mergefile:
-        try:
-            cmd = ['/sbin/ifquery', '%s' %swp_intf, '-i', '%s' %args.mergefile]
-            outbuf = subprocess.check_output(cmd, stderr=subprocess.STDOUT)
-        except Exception, e:
-            # no interface found gen latest
-            pass
-    if not outbuf:
-        outbuf = 'auto %s\niface %s\n\n' %(swp_intf, swp_intf)
-    return outbuf
-
-def interfaces_print_swp_defaults(swp_intfs):
-    print_swp_defaults_header()
-    outbuf = ''
-    for i in swp_intfs:
-        outbuf += interfaces_print_swp_default(i)
-    print outbuf
-
-def interfaces_print_bridge_default(swp_intfs):
-    print_bridge_untagged_defaults_header()
-    outbuf = 'auto bridge-untagged\n' 
-    outbuf += 'iface bridge-untagged\n'
-    outbuf += '  bridge-ports \\\n'
-    linen = 5
-    ports = ''
-    for i in range(0, len(swp_intfs), linen):
-        if ports:
-            ports += ' \\\n'
-        ports += '      %s' %(' '.join(swp_intfs[i:i+linen]))
-    outbuf += ports
-    print outbuf
-
-def populate_argparser(argparser):
-    group = argparser.add_mutually_exclusive_group(required=False)
-    group.add_argument('-s', '--swp-defaults', action='store_true',
-                       dest='swpdefaults', help='generate swp defaults file')
-    group.add_argument('-b', '--bridge-default', action='store_true',
-                       dest='bridgedefault',
-                       help='generate default untagged bridge')
-    argparser.add_argument('-m', '--merge', dest='mergefile', help='merge ' +
-                           'new generated iface content with the old one')
-
-argparser =  argparse.ArgumentParser(description='ifupdown interfaces file gen helper')
-populate_argparser(argparser)
-args = argparser.parse_args(sys.argv[1:])
-
-if not args.swpdefaults and not args.bridgedefault:
-    argparser.print_help()
-    exit(1)
-
-if args.bridgedefault and args.mergefile:
-    print 'error: mergefile option currently only supported with -s'
-    argparser.print_help()
-    exit(1)
-
-swp_intfs = get_swp_interfaces()
-if not swp_intfs:
-    print 'error: no ports found'
-    exit(1)
-
-if args.swpdefaults:
-    interfaces_print_swp_defaults(swp_intfs)
-elif args.bridgedefault:
-    interfaces_print_bridge_default(swp_intfs)
-else:
-    argparser.print_help()
diff --git a/ifupdown2/docs/examples/interfaces b/ifupdown2/docs/examples/interfaces
deleted file mode 100644 (file)
index df05fc1..0000000
+++ /dev/null
@@ -1,74 +0,0 @@
-# This file describes the network interfaces available on your system
-# and how to activate them. For more information, see interfaces(5).
-
-# The loopback network interface
-auto lo
-iface lo inet loopback
-
-# The primary network interface
-auto eth0
-iface eth0 inet dhcp
-
-#source /etc/network/interfaces.d/template.bridges
-
-# swp interface
-auto swp30
-iface swp30
-    address 12.0.0.4/24
-    address 12.0.0.6/24
-    address 2000:1000:1000:1000:3::5/128
-    mtu 1600
-    alias "test network"
-    link-duplex full
-    link-speed 1000
-    link-autoneg off
-
-# bond interface
-auto bond3
-iface bond3 inet static
-    address 100.0.0.4/16
-    bond-slaves swp1 swp2
-    bond-mode 802.3ad
-    bond-miimon 100
-    bond-use-carrier 1
-    bond-lacp-rate 1
-    bond-min-links 1
-    bond-xmit_hash_policy layer3+4
-
-# bond interface
-auto bond4
-iface bond4 inet static
-    address 100.0.0.6/16
-    bond-slaves swp3 swp4
-    bond-mode 802.3ad
-    bond-miimon 100
-    bond-use-carrier 1
-    bond-lacp-rate 1
-    bond-min-links 1
-    bond-xmit_hash_policy layer3+4
-
-# bond interface
-auto br0
-iface br0
-    address 12.0.0.4/24
-    address 12.0.0.6/24
-    address 2000:1000:1000:1000:3::5/128
-    bridge-ports bond3 bond4 swp5 swp8
-    bridge-stp on
-
-# vlan interface on bond
-auto bond3.2000
-iface bond3.2000 inet static
-    address 100.1.0.4/16
-
-auto bond4.2000
-iface bond4.2000 inet static
-    address 100.1.0.6/16
-
-auto br2000
-iface br2000 inet6 static
-    address 2001:dad:beef::4/64
-    bridge-ports bond3.2000 bond4.2000 swp5.2000
-    bridge-stp on
-    mstpctl-treeprio 61440
-    mstpctl-portp2p bond3.2000=yes bond4.2000=yes
diff --git a/ifupdown2/docs/examples/interfaces_bridge_igmp_mstp b/ifupdown2/docs/examples/interfaces_bridge_igmp_mstp
deleted file mode 100644 (file)
index f4916f4..0000000
+++ /dev/null
@@ -1,48 +0,0 @@
-
-#
-# This example lists all attributes for bridge configuration.
-# The attributes with mstpctl- prefix indicate mstp settings on a bridge.
-# The attributes with bridge- prefix indicate bridge stp and igmp attributes.
-# Except bridge-ports, none of the other attributes are required. Default
-# values are documented in the ifupdown-addons-interfaces(5) man page.
-#
-# The bridge in the example below is a vlan unaware bridge (classic linux
-# bridge)
-#
-auto br-300
-iface br-300 inet static
-           address 12.0.0.3/24
-           bridge-ports swp13.300 swp14.300
-           bridge-stp on
-           mstpctl-maxage 20
-           mstpctl-fdelay 15
-           mstpctl-maxhops 20
-           mstpctl-txholdcount 6
-           mstpctl-forcevers rstp
-           mstpctl-portpathcost swp13.300=0 swp14.300=0
-           mstpctl-portadminedge swp13.300=no swp14.300=no
-           mstpctl-portautoedge swp13.300=yes swp14.300=yes
-           mstpctl-portp2p swp13.300=no swp13.300=no
-           mstpctl-portrestrrole swp13.300=no swp14.300=no
-           mstpctl-bpduguard swp13.300=no swp14.300=no
-           mstpctl-portrestrtcn swp13.300=no swp14.300=no
-           mstpctl-treeprio 32768
-           mstpctl-treeportprio swp13.300=128
-           mstpctl-hello 2
-           mstpctl-portnetwork swp13.300=no
-           bridge-mclmc 3
-           bridge-mcrouter 0
-           bridge-mcsnoop  1
-           bridge-mcsqc    3
-           bridge-mcqifaddr 1
-           bridge-mcquerier 1
-           bridge-hashel 3
-           bridge-hashmax 4
-           bridge-mclmi 3
-           bridge-mcmi 200
-           bridge-mcqpi 200
-           bridge-mcqi  100
-           bridge-mcqri 20
-           bridge-mcsqi 50
-           bridge-portmcrouter swp13.300=0
-           bridge-portmcfl     swp13.300=1
diff --git a/ifupdown2/docs/examples/interfaces_bridge_template_func b/ifupdown2/docs/examples/interfaces_bridge_template_func
deleted file mode 100644 (file)
index 61003d6..0000000
+++ /dev/null
@@ -1,33 +0,0 @@
-#
-# mako template function to create a bridge
-#
-# mako defs provide the advantage of declaring predefined functions in
-# separate files.
-#
-# Below is an example that illustrates how to define such functions and use
-# them in the /etc/network/interfaces file to create bridges
-#
-# This file defines a function makebr to create a bridge. The arguments to the
-# function are vlan and ip address of the bridge.
-#
-# The default directory for template functions is
-# /etc/network/ifupdown2/templates/. Copy this file under the template
-# dir (create the directory if does not exist)
-#
-# To use this template function in /etc/network/interfaces, add the following
-# to the /etc/network/interfaces file:
-#
-# <%namespace name="bridge" file="/bridge_template"/>
-#
-# ${bridge.makebr(1096, "10.0.23.2/24")}
-# ${bridge.makebr(1097, "10.0.23.3/24")}
-#
-#
-
-<%def name="makebr(vlan, addr)">
-auto br${vlan}
-iface br${vlan} inet static
-    address ${addr}
-    bridge-ports swp1.${vlan} swp2.${vlan}
-    bridge-stp on
-</%def>
diff --git a/ifupdown2/docs/examples/interfaces_with_template b/ifupdown2/docs/examples/interfaces_with_template
deleted file mode 100644 (file)
index af9d571..0000000
+++ /dev/null
@@ -1,24 +0,0 @@
-#
-# Example interfaces file using mako templates
-#
-# The below section can be copied into
-# /etc/network/interfaces file 
-# or
-# to a file under /etc/network/interfaces.d/
-# and include in the interfaces file using the
-# 'source' command.
-#
-# see manpage interfaces(5) for details
-# 
-#
-
-%for v in range(1000,1100):
-auto vlan-${v}
-iface vlan-${v} inet static
-    bridge-ports glob swp1-6.${v}
-    bridge-stp on
-    bridge-ageing 200
-    bridge-maxage 10
-    bridge-fd 10
-%endfor
-
diff --git a/ifupdown2/docs/examples/vlan_aware_bridges/interfaces.basic b/ifupdown2/docs/examples/vlan_aware_bridges/interfaces.basic
deleted file mode 100644 (file)
index 7506175..0000000
+++ /dev/null
@@ -1,25 +0,0 @@
-#
-# vlan-aware bridge simple example
-#
-# 'bridge' is a vlan aware bridge with all ports (swp1-52).
-# native vlan is by default 1
-#
-# 'bridge-vids' attribute is used to declare vlans.
-# 'bridge-pvid' attribute is used to specify native vlans if other than 1
-# 'bridge-access' attribute is used to declare access port
-# 
-
-#
-# ports swp1-swp52 are trunk ports which inherit vlans from 'bridge'
-# ie vlans 310 700 707 712 850 910
-      
-#
-# the following is a vlan aware bridge with ports swp1-swp52
-# It has stp on
-#
-auto bridge
-iface bridge
-      bridge-vlan-aware yes
-      bridge-ports glob swp1-52
-      bridge-stp on
-      bridge-vids 310 700 707 712 850 910
diff --git a/ifupdown2/docs/examples/vlan_aware_bridges/interfaces.vlan_prune_and_access_ports b/ifupdown2/docs/examples/vlan_aware_bridges/interfaces.vlan_prune_and_access_ports
deleted file mode 100644 (file)
index 9641a82..0000000
+++ /dev/null
@@ -1,59 +0,0 @@
-#
-# vlan-aware bridge access ports and pruned vlan example
-#
-# 'bridge' is a vlan aware bridge with all ports (swp1-52).
-# native vlan is by default 1
-#
-# 'bridge-vids' attribute is used to declare vlans.
-# 'bridge-pvid' attribute is used to specify native vlans if other than 1
-# 'bridge-access' attribute is used to declare access port
-#
-# 
-
-# The following is an access port to vlan 310, no trunking
-auto swp1
-iface swp1
-      bridge-access 310
-      mstpctl-portadminedge yes
-      mstpctl-bpduguard yes
-
-# The following is a truk port that is "pruned".
-# native vlan is 1, but only .1q tags of 707, 712, 850 are
-# sent and received
-#
-auto swp2
-iface swp2
-      bridge-vids 707 712 850
-      mstpctl-portadminedge yes
-      mstpctl-bpduguard yes
-     
-# The following port is the trunk uplink and inherits all vlans
-# from 'bridge'
-auto swp49
-iface swp49
-      mstpctl-portpathcost 10
-      # Enable bridge assurance on uplink port using 'portnetwork' attribute
-      mstpctl-portnetwork yes
-
-# The following port is the trunk uplink and inherits all vlans
-# from 'bridge'
-auto swp50
-iface swp50
-      mstpctl-portpathcost 0
-      # Enable bridge assurance on uplink port using 'portnetwork' attribute
-      mstpctl-portnetwork yes
-
-#
-# ports swp3-swp48 are trunk ports which inherit vlans from the 'bridge'
-# ie vlans 310,700,707,712,850,910
-      
-#
-# the following is a vlan aware bridge with ports swp1-swp52
-# It has stp on
-#
-auto bridge
-iface bridge
-      bridge-vlan-aware yes
-      bridge-ports glob swp1-52
-      bridge-stp on
-      bridge-vids 310 700 707 712 850 910
diff --git a/ifupdown2/docs/examples/vlan_aware_bridges/interfaces.with_bonds b/ifupdown2/docs/examples/vlan_aware_bridges/interfaces.with_bonds
deleted file mode 100644 (file)
index f3425dd..0000000
+++ /dev/null
@@ -1,92 +0,0 @@
-#
-# vlan-aware bridge with bonds example
-#
-# uplink1, peerlink and downlink are bond interfaces.
-# 'bridge' is a vlan aware bridge with ports uplink1, peerlink
-# and downlink (swp2-20).
-# 
-# native vlan is by default 1
-#
-# 'bridge-vids' attribute is used to declare vlans.
-# 'bridge-pvid' attribute is used to specify native vlans if other than 1
-# 'bridge-access' attribute is used to declare access port
-# 
-auto lo
-iface lo
-
-auto eth0
-iface eth0 inet dhcp
-
-# bond interface
-auto uplink1
-iface uplink1
-    bond-slaves swp32
-    bond-mode 802.3ad
-    bond-miimon 100
-    bond-use-carrier 1
-    bond-lacp-rate 1
-    bond-min-links 1
-    bond-xmit-hash-policy layer2
-    bridge-vids 2000-2079
-
-# bond interface
-auto peerlink
-iface peerlink
-    bond-slaves swp30 swp31
-    bond-mode 802.3ad
-    bond-miimon 100
-    bond-use-carrier 1
-    bond-lacp-rate 1
-    bond-min-links 1
-    bond-xmit-hash-policy layer3+4
-    bridge-vids 2000-2079 4094
-
-# bond interface
-auto downlink
-iface downlink
-    bond-slaves swp1
-    bond-mode 802.3ad
-    bond-miimon 100
-    bond-use-carrier 1
-    bond-lacp-rate 1
-    bond-min-links 1
-    bond-xmit-hash-policy layer3+4
-    bridge-vids 2000-2079
-
-#
-# Declare vlans for all swp ports
-# swp2-20 get vlans from 2004 to 2022.
-# The below uses mako templates to generate iface sections
-# with vlans for swp ports
-#
-%for port, vlanid in zip(range(2, 20), range(2004, 2022)) :
-    auto swp${port}
-    iface swp${port}
-        bridge-vids ${vlanid}
-
-%endfor
-
-# svi vlan 4094
-auto bridge.4094
-iface bridge.4094
-    address 11.100.1.252/24
-
-# l2 attributes for vlan 4094
-auto bridge.4094
-vlan bridge.4094
-    bridge-igmp-querier-src 172.16.101.1
-
-#
-# vlan aware bridge
-#
-auto bridge
-iface bridge
-    bridge-vlan-aware yes
-    bridge-ports uplink1 peerlink downlink glob swp2-20
-    bridge-stp on
-
-# svi peerlink vlan
-auto peerlink.4094
-iface peerlink.4094
-    address 192.168.10.1/30
-    broadcast 192.168.10.3
diff --git a/ifupdown2/docs/examples/vlan_aware_bridges/interfaces.with_clag b/ifupdown2/docs/examples/vlan_aware_bridges/interfaces.with_clag
deleted file mode 100644 (file)
index 8cdccc9..0000000
+++ /dev/null
@@ -1,87 +0,0 @@
-#
-# vlan-aware bridge with clag example
-#
-#
-# 'bridge' is a vlan aware bridge with ports:
-#      'peer-bond spine-bond glob host-bond-0[1-2]'
-#
-# All ports inherit 'vlans 10 20-23' from the 'bridge-vids' attribute
-# under the bridge
-# 
-# native vlan is by default 1
-#
-# 'bridge-vids' attribute is used to declare vlans.
-# 'bridge-pvid' attribute is used to specify native vlans if other than 1
-# 'bridge-access' attribute is used to declare access port
-# 
-# 'spine-bond host-bond-0[1-2]' are clag bonds and will be considered by
-# clagd for dual connection. clag-id has to be a non-zero and has to match
-# across the peer switches for the bonds to become dual connected.
-
-# spine bond
-#
-auto spine-bond
-iface spine-bond
-      bond-slaves glob swp19-22
-      bond-mode 802.3ad
-      bond-miimon 100
-      bond-use-carrier 1
-      bond-lacp-rate 1
-      bond-min-links 1
-      bond-xmit-hash-policy layer3+4
-      clag-id 100
-
-# mlag bond and peer interface
-#
-auto peer-bond
-iface peer-bond
-      bond-slaves glob swp23-24
-      bond-mode 802.3ad
-      bond-miimon 100
-      bond-use-carrier 1
-      bond-lacp-rate 1
-      bond-min-links 1
-      bond-xmit-hash-policy layer3+4
-
-# sub-interface for clagd communication
-#
-auto peer-bond.4094
-iface peer-bond.4094
-      address 169.254.0.1/30
-      clagd-peer-ip 169.254.0.2
-      clagd-sys-mac 44:38:39:ff:00:01
-      #clagd-priority 4096
-      # Please see man clagd for more options
-      # clagd-args --peerTimeout 30
-
-# host ports
-#
-auto host-bond-01
-iface host-bond-01
-      bond-slaves swp1
-      bond-mode 802.3ad
-      bond-miimon 100
-      bond-use-carrier 1
-      bond-lacp-rate 1
-      bond-min-links 1
-      bond-xmit-hash-policy layer3+4
-      clag-id 1
-
-auto host-bond-02
-iface host-bond-02
-      bond-slaves swp2
-      bond-mode 802.3ad
-      bond-miimon 100
-      bond-use-carrier 1
-      bond-lacp-rate 1
-      bond-min-links 1
-      bond-xmit-hash-policy layer3+4
-      clag-id 2
-
-# the bridge
-auto bridge
-iface bridge
-      bridge-vlan-aware yes
-      bridge-ports peer-bond spine-bond glob host-bond-0[1-2]
-      bridge-stp on
-      bridge-vids 10 20-23
diff --git a/ifupdown2/docs/source/addonsapiref.rst b/ifupdown2/docs/source/addonsapiref.rst
deleted file mode 100644 (file)
index 0954d27..0000000
+++ /dev/null
@@ -1,61 +0,0 @@
-Documentation for the ifupdownaddons default addons modules
-***********************************************************
-
-address
-=======
-
-.. automodule:: address
-
-.. autoclass:: address
-   :members: run, get_ops
-
-
-bridge
-======
-
-.. automodule:: bridge
-
-.. autoclass:: bridge
-   :members: run, get_ops
-
-dhcp
-====
-
-.. automodule:: dhcp
-
-.. autoclass:: dhcp
-
-ethtool
-=======
-
-.. automodule:: ethtool
-
-.. autoclass:: ethtool
-
-ifenslave
-=========
-
-.. automodule:: ifenslave
-
-.. autoclass:: ifenslave
-
-mstpctl
-=======
-
-.. automodule:: mstpctl
-
-.. autoclass:: mstpctl
-
-usercmds
-========
-
-.. automodule:: usercmds
-
-.. autoclass:: usercmds
-
-vlan
-====
-
-.. automodule:: vlan
-
-.. autoclass:: vlan
diff --git a/ifupdown2/docs/source/addonshelperapiref.rst b/ifupdown2/docs/source/addonshelperapiref.rst
deleted file mode 100644 (file)
index 01d9a41..0000000
+++ /dev/null
@@ -1,44 +0,0 @@
-Documentation for the ifupdownaddons package helper modules
-***********************************************************
-
-This package contains modules that provide helper methods
-for ifupdown2 addon modules to interact directly with tools
-like iproute2, brctl etc.
-
-
-bridgeutils
-===========
-
-Helper module to work with bridgeutil commands
-
-.. automodule:: bridgeutils
-
-.. autoclass:: brctl
-
-ifenslaveutil
-=============
-
-Helper module to interact with linux api to create bonds.
-Currently this is via sysfs.
-
-.. automodule:: ifenslaveutil
-
-.. autoclass:: ifenslaveutil
-
-dhclient
-========
-
-Helper module to interact with dhclient tools.
-
-.. automodule:: dhclient
-
-.. autoclass:: dhclient
-
-iproute2
-========
-
-Helper module to interact with iproute2 tools.
-
-.. automodule:: iproute2
-
-.. autoclass:: iproute2
diff --git a/ifupdown2/docs/source/apiref.rst b/ifupdown2/docs/source/apiref.rst
deleted file mode 100644 (file)
index f30dc39..0000000
+++ /dev/null
@@ -1,65 +0,0 @@
-Documentation for the Code
-**************************
-
-
-ifupdownmain
-============
-
-ifupdownmain is the main ifupdown module.
-
-.. automodule:: ifupdownmain
-
-.. autoclass:: ifupdownMain
-   :members: up, down, reload, query
-
-iface
-=====
-
-.. automodule:: iface
-
-.. autoclass:: iface
-   :members: state, status, flags, priv_flags, refcnt, lowerifaces, upperifaces, add_to_upperifaces, get_attr_value, get_attr_value_first, get_attr_value_n, update_config, update_config_with_status, get_config_attr_status, compare, dump_raw, dump, dump_pretty
-
-.. autoclass:: ifaceState
-
-.. autoclass:: ifaceStatus
-
-.. autoclass:: ifaceJsonEncoder
-
-scheduler
-=========
-
-.. automodule:: scheduler
-
-.. autoclass:: ifaceScheduler
-   :members: sched_ifaces
-
-.. autoclass:: ifaceSchedulerFlags
-
-
-networkinterfaces
-=================
-
-.. automodule:: networkinterfaces
-
-.. autoclass:: networkInterfaces
-   :members: load, subscribe
-
-statemanager
-============
-
-.. automodule:: statemanager
-
-.. autoclass:: pickling
-   :members: save, save_obj, load
-
-.. autoclass:: stateManager
-   :members: read_saved_state, save_state
-
-graph
-=====
-
-.. automodule:: graph
-
-.. autoclass:: graph
-   :members: topological_sort_graphs_all, generate_dots
diff --git a/ifupdown2/docs/source/conf.py b/ifupdown2/docs/source/conf.py
deleted file mode 100644 (file)
index 01bc5cc..0000000
+++ /dev/null
@@ -1,250 +0,0 @@
-# -*- coding: utf-8 -*-
-#
-# ifupdown2 documentation build configuration file, created by
-# sphinx-quickstart on Sun Jul  6 23:49:20 2014.
-#
-# This file is execfile()d with the current directory set to its containing dir.
-#
-# Note that not all possible configuration values are present in this
-# autogenerated file.
-#
-# All configuration values have a default; values that are commented out
-# serve to show the default.
-
-import sys, os
-
-# If extensions (or modules to document with autodoc) are in another directory,
-# add these directories to sys.path here. If the directory is relative to the
-# documentation root, use os.path.abspath to make it absolute, like shown here.
-sys.path.insert(0, os.path.abspath('../../ifupdown'))
-sys.path.append(os.path.abspath('../../addons'))
-sys.path.append(os.path.abspath('../../'))
-sys.path.append(os.path.abspath('../../ifupdownaddons'))
-sys.path.append(os.path.abspath('../../../ifupdown2'))
-
-# -- General configuration -----------------------------------------------------
-
-# If your documentation needs a minimal Sphinx version, state it here.
-#needs_sphinx = '1.0'
-
-# Add any Sphinx extension module names here, as strings. They can be extensions
-# coming with Sphinx (named 'sphinx.ext.*') or your custom ones.
-extensions = ['sphinx.ext.autodoc', 'sphinx.ext.intersphinx', 'sphinx.ext.todo']
-
-# Add any paths that contain templates here, relative to this directory.
-templates_path = ['_templates']
-
-# The suffix of source filenames.
-source_suffix = '.rst'
-
-# The encoding of source files.
-#source_encoding = 'utf-8-sig'
-
-# The master toctree document.
-master_doc = 'index'
-
-# General information about the project.
-project = u'ifupdown2'
-copyright = u'2014, Roopa Prabhu'
-
-# The version info for the project you're documenting, acts as replacement for
-# |version| and |release|, also used in various other places throughout the
-# built documents.
-#
-# The short X.Y version.
-version = '0.1'
-# The full version, including alpha/beta/rc tags.
-release = '0.1'
-
-# The language for content autogenerated by Sphinx. Refer to documentation
-# for a list of supported languages.
-#language = None
-
-# There are two options for replacing |today|: either, you set today to some
-# non-false value, then it is used:
-#today = ''
-# Else, today_fmt is used as the format for a strftime call.
-#today_fmt = '%B %d, %Y'
-
-# List of patterns, relative to source directory, that match files and
-# directories to ignore when looking for source files.
-exclude_patterns = []
-
-# The reST default role (used for this markup: `text`) to use for all documents.
-#default_role = None
-
-# If true, '()' will be appended to :func: etc. cross-reference text.
-#add_function_parentheses = True
-
-# If true, the current module name will be prepended to all description
-# unit titles (such as .. function::).
-#add_module_names = True
-
-# If true, sectionauthor and moduleauthor directives will be shown in the
-# output. They are ignored by default.
-#show_authors = False
-
-# The name of the Pygments (syntax highlighting) style to use.
-pygments_style = 'sphinx'
-
-# A list of ignored prefixes for module index sorting.
-#modindex_common_prefix = []
-
-
-# -- Options for HTML output ---------------------------------------------------
-
-# The theme to use for HTML and HTML Help pages.  See the documentation for
-# a list of builtin themes.
-html_theme = 'default'
-
-# Theme options are theme-specific and customize the look and feel of a theme
-# further.  For a list of options available for each theme, see the
-# documentation.
-#html_theme_options = {}
-
-# Add any paths that contain custom themes here, relative to this directory.
-#html_theme_path = []
-
-# The name for this set of Sphinx documents.  If None, it defaults to
-# "<project> v<release> documentation".
-#html_title = None
-
-# A shorter title for the navigation bar.  Default is the same as html_title.
-#html_short_title = None
-
-# The name of an image file (relative to this directory) to place at the top
-# of the sidebar.
-#html_logo = None
-
-# The name of an image file (within the static path) to use as favicon of the
-# docs.  This file should be a Windows icon file (.ico) being 16x16 or 32x32
-# pixels large.
-#html_favicon = None
-
-# Add any paths that contain custom static files (such as style sheets) here,
-# relative to this directory. They are copied after the builtin static files,
-# so a file named "default.css" will overwrite the builtin "default.css".
-html_static_path = ['_static']
-
-# If not '', a 'Last updated on:' timestamp is inserted at every page bottom,
-# using the given strftime format.
-#html_last_updated_fmt = '%b %d, %Y'
-
-# If true, SmartyPants will be used to convert quotes and dashes to
-# typographically correct entities.
-#html_use_smartypants = True
-
-# Custom sidebar templates, maps document names to template names.
-#html_sidebars = {}
-
-# Additional templates that should be rendered to pages, maps page names to
-# template names.
-#html_additional_pages = {}
-
-# If false, no module index is generated.
-#html_domain_indices = True
-
-# If false, no index is generated.
-#html_use_index = True
-
-# If true, the index is split into individual pages for each letter.
-#html_split_index = False
-
-# If true, links to the reST sources are added to the pages.
-#html_show_sourcelink = True
-
-# If true, "Created using Sphinx" is shown in the HTML footer. Default is True.
-#html_show_sphinx = True
-
-# If true, "(C) Copyright ..." is shown in the HTML footer. Default is True.
-#html_show_copyright = True
-
-# If true, an OpenSearch description file will be output, and all pages will
-# contain a <link> tag referring to it.  The value of this option must be the
-# base URL from which the finished HTML is served.
-#html_use_opensearch = ''
-
-# This is the file name suffix for HTML files (e.g. ".xhtml").
-#html_file_suffix = None
-
-# Output file base name for HTML help builder.
-htmlhelp_basename = 'ifupdown2doc'
-
-
-# -- Options for LaTeX output --------------------------------------------------
-
-latex_elements = {
-# The paper size ('letterpaper' or 'a4paper').
-#'papersize': 'letterpaper',
-
-# The font size ('10pt', '11pt' or '12pt').
-#'pointsize': '10pt',
-
-# Additional stuff for the LaTeX preamble.
-#'preamble': '',
-}
-
-# Grouping the document tree into LaTeX files. List of tuples
-# (source start file, target name, title, author, documentclass [howto/manual]).
-latex_documents = [
-  ('index', 'ifupdown2.tex', u'ifupdown2 Documentation',
-   u'Roopa Prabhu', 'manual'),
-]
-
-# The name of an image file (relative to this directory) to place at the top of
-# the title page.
-#latex_logo = None
-
-# For "manual" documents, if this is true, then toplevel headings are parts,
-# not chapters.
-#latex_use_parts = False
-
-# If true, show page references after internal links.
-#latex_show_pagerefs = False
-
-# If true, show URL addresses after external links.
-#latex_show_urls = False
-
-# Documents to append as an appendix to all manuals.
-#latex_appendices = []
-
-# If false, no module index is generated.
-#latex_domain_indices = True
-
-
-# -- Options for manual page output --------------------------------------------
-
-# One entry per manual page. List of tuples
-# (source start file, name, description, authors, manual section).
-man_pages = [
-    ('index', 'ifupdown2', u'ifupdown2 Documentation',
-     [u'Roopa Prabhu'], 1)
-]
-
-# If true, show URL addresses after external links.
-#man_show_urls = False
-
-
-# -- Options for Texinfo output ------------------------------------------------
-
-# Grouping the document tree into Texinfo files. List of tuples
-# (source start file, target name, title, author,
-#  dir menu entry, description, category)
-texinfo_documents = [
-  ('index', 'ifupdown2', u'ifupdown2 Documentation',
-   u'Roopa Prabhu', 'ifupdown2', 'One line description of project.',
-   'Miscellaneous'),
-]
-
-# Documents to append as an appendix to all manuals.
-#texinfo_appendices = []
-
-# If false, no module index is generated.
-#texinfo_domain_indices = True
-
-# How to display URL addresses: 'footnote', 'no', or 'inline'.
-#texinfo_show_urls = 'footnote'
-
-
-# Example configuration for intersphinx: refer to the Python standard library.
-intersphinx_mapping = {'http://docs.python.org/': None}
diff --git a/ifupdown2/docs/source/developmentcorner.rst b/ifupdown2/docs/source/developmentcorner.rst
deleted file mode 100644 (file)
index 960d688..0000000
+++ /dev/null
@@ -1,72 +0,0 @@
-Development Corner
-==================
-
-Getting started
----------------
-Unlike original ifupdown, all interface configuration is moved to external
-python modules. That includes inet, inet6 and dhcp configurations.
-
-* if you are looking at fixing bugs or adding new features to the ifupdown2
-  infrastructure package, pls look at the apiref, documentation and code
-  for python-ifupdown2
-
-
-Writing a ifupdown2 addon module
---------------------------------
-Addon modules are a nice way to add additional functionality to ifupdown2.
-Typically a new addon module will include support for a new network interface
-configuration which is not already supported by existing ifupdown2 addon
-modules.
-
-ifupdown2 addon modules are written in python. python-ifupdown2 package
-comes with default addon modules. All addon modules are installed under
-/usr/share/ifupdownaddons directory.
-
-The center of the universe for an addon module is the 'class iface' object
-exported by the python-ifupdown2 package.
-
-The iface object is modeled after an iface entry in the user provided network
-configuration file (eg. /etc/network/interfaces). For more details see
-the api reference for the iface class.
-
-ifupdown2 dynamically loads a python addon module. It expects the addon module
-to implement a few methods.
-
-* all addon modules must inherit from moduleBase class
-* the module must implement a class by the same name
-* the network interface object (class iface) and the operation to be performed
-  is passed to the modules. Operation can be any of 'pre-up', 'up', 'post-up',
-  'pre-down', 'down', 'post-down', 'query-check', 'query-running'.
-  The module can choose to support a subset or all operations.
-  In cases when the operation is query-check, the module must compare between
-  the given and running state and return the checked state of the object in
-  queryobjcur passed as argument to the run menthod.
-* the python addon class must provide a few methods:
-    * run() : method to configure the interface.
-    * get_ops() : must return a list of operations it supports.
-      eg: 'pre-up', 'post-down'
-    * get_dependent_ifacenames() : must return a list of interfaces the
-      supported interface is dependent on. This is used to build the
-      dependency list for sorting and executing interfaces in dependency order.
-    * if the module supports -r option to ifquery, ie ability to construct the
-      ifaceobj from running state, it can optionally implement the
-      get_dependent_ifacenames_running() method, to return the list of
-      dependent interfaces derived from running state of the interface.
-      This is different from get_dependent_ifacenames() where the dependent
-      interfaces are derived from the interfaces config file (provided by the
-      user).
-    * provide a dictionary of all supported attributes in the _modinfo
-      attribute. This is useful for syntax help and man page generation.
-
-python-ifupdown2 package also installs ifupdownaddons python package
-that contains helper modules for all addon modules.
-
-see example address handling module /usr/share/ifupdownaddons/address.py
-
-API reference
--------------
-.. toctree::
-   :maxdepth: 2
-
-   addonsapiref.rst
-   addonshelperapiref.rst
diff --git a/ifupdown2/docs/source/gettingstarted.rst b/ifupdown2/docs/source/gettingstarted.rst
deleted file mode 100644 (file)
index 4d7f6cb..0000000
+++ /dev/null
@@ -1,27 +0,0 @@
-Getting Started
-===============
-
-Prerequisites
--------------
-* python-ifupdown2 is currently only tested on debian wheezy
-* python-ifupdown2 needs python version 2.6 or greater
-* Depends on: python-stdeb (for deb builds), python-docutils
-  (for rst2man), python-argcomplete, 'python-ipaddr'
-* Depends on python-gvgen package for printing interface graphs (this will be made optional in the future)
-* Optional dependency for template engine: python-mako
-
-
-Building
---------
-$git clone <ifupdown2 git url> ifupdown2
-
-$cd ifupdown2/ifupdown2
-
-$./build.sh
-
-Installing
-----------
-install generated python-ifupdown2-<ver>.deb
-
-$dpkg -i <python-ifupdown2-<ver>.deb
-
diff --git a/ifupdown2/docs/source/images/interfaces.png b/ifupdown2/docs/source/images/interfaces.png
deleted file mode 100644 (file)
index fda6d92..0000000
Binary files a/ifupdown2/docs/source/images/interfaces.png and /dev/null differ
diff --git a/ifupdown2/docs/source/images/interfaces_all.png b/ifupdown2/docs/source/images/interfaces_all.png
deleted file mode 100644 (file)
index 3e1ae9c..0000000
Binary files a/ifupdown2/docs/source/images/interfaces_all.png and /dev/null differ
diff --git a/ifupdown2/docs/source/index.rst b/ifupdown2/docs/source/index.rst
deleted file mode 100644 (file)
index fde8c80..0000000
+++ /dev/null
@@ -1,25 +0,0 @@
-.. ifupdown2 documentation master file, created by
-   sphinx-quickstart on Sun Jul  6 23:49:20 2014.
-   You can adapt this file completely to your liking, but it should at least
-   contain the root `toctree` directive.
-
-Welcome to ifupdown2's documentation!
-=====================================
-
-Contents:
-
-.. toctree::
-   :maxdepth: 2
-
-   intro.rst
-   gettingstarted.rst
-   userguide.rst
-   developmentcorner.rst
-
-Indices and tables
-==================
-
-* :ref:`genindex`
-* :ref:`modindex`
-* :ref:`search`
-
diff --git a/ifupdown2/docs/source/intro.rst b/ifupdown2/docs/source/intro.rst
deleted file mode 100644 (file)
index 7293e3f..0000000
+++ /dev/null
@@ -1,31 +0,0 @@
-python-ifupdown2
-----------------
-
-The python-ifupdown2 package provides the infrastructure for
-parsing /etc/network/interfaces file, loading, scheduling, template parsing,
-state management and interface dependency generation of interfaces.
-It dynamically loads python addon modules from /usr/share/ifupdownmodules.
-To remain compatible with other packages that depend on ifupdown, it also
-executes scripts under /etc/network/. To make the transition smoother, a
-python module under /usr/share/ifupdownmodules will override a script by
-the same name under /etc/network/. ifupdown2 publishes an interface object which
-is passed to all loadble python addon modules. All lodable modules are
-called for every interface declared in the /etc/network/interfaces file.
-
-Addon modules are responsible for applying interface configuration.
-python-ifupdown2 ships with a set of default addon modules. Each module can
-declare its own set of supported attributes. Each module is passed the iface
-object (which is a representation of /etc/network/interfaces
-iface entry). Each module is also passed the operation to be performed.
-
-Example modules are /usr/share/ifupdownmodules/address.py,
-/usr/share/ifupdownmodules/bridge.py etc
-
-The order in which these modules are invoked is listed in
-/var/lib/ifupdownaddons/addons.conf. There is an ifaddon utility in the works
-to better manage the module ordering.
-
-For more details on adding an addon module, see the section on adding python
-modules. For details on how to write a module, see the api reference and
-development documentation.
-
diff --git a/ifupdown2/docs/source/userguide.rst b/ifupdown2/docs/source/userguide.rst
deleted file mode 100644 (file)
index c06e9d2..0000000
+++ /dev/null
@@ -1,447 +0,0 @@
-.. index:: ifupdown
-
-.. _ifupdown:
-
-**********
-User Guide
-**********
-
-Keep the following points in mind before you start configuring interfaces using 
-``ifupdown2``:
-
-* IPv4 and IPv6 addresses for an interface can be listed in the same ``iface`` 
-  section. For examples, see ``/usr/share/doc/python-ifupdown2/examples/``.
-
-* Do not use a legacy interface alias. They are only supported for backward 
-  compatibility with ``ifupdown``. They do get configured, but ``ifquery`` has 
-  problems recognizing them.
-  
-* ``ifupdown`` only understands interfaces that were configured using 
-  ``ifupdown``. Any interfaces created with a command other than ``ifupdown`` 
-  (like ``brctl``) must be de-configured in the same manner.
-
-* Use globs for port lists wherever applicable. Regular expressions work as well, 
-  however regular expressions require all matching interfaces to be present in 
-  the ``interfaces`` file. And declaring all interfaces in the ``interfaces`` 
-  file leads to losing all the advantages that built-in interfaces provide.
-
-* Extensions to ``ifquery`` help with validation and debugging.
-
-* By default, ``ifupdown`` is quiet; use the verbose option ``-v`` when you want 
-  to know what is going on when bringing an interface down or up.
-  
-Contents
-========
-* `Commands`_
-* `Man Pages`_
-* `Configuration Files`_
-* `ifupdown Built-in Interfaces`_
-* `ifupdown Interface Dependencies`_
-* `Configuring IP Addresses`_
-* `Specifying User Commands`_
-* `Sourcing Interface File Snippets`_
-* `Using Globs for Port Lists`_
-* `Using Templates`_
-* `Using ifquery to Validate and Debug Interface Configurations`_
-* `Useful Links`_
-
-Commands
-========
-
-* ifdown
-* ifquery
-* ifreload
-* ifup
-
-Man Pages
-=========
-
-* man ifdown(8)
-* man ifquery(8)
-* man ifreload
-* man ifup(8)
-* man ifupdown-addons-interfaces(5)
-* man interfaces(5)
-
-Configuration Files
-===================
-
-* /etc/network/interfaces
-
-    
-ifupdown Built-in Interfaces
-============================
-
-``ifupdown`` understands VLAN interfaces and physical interfaces that may appear
-as dependents. There is no need to list them unless they need the specific
-configuration or they need to match a regular expression used in the
-``interfaces`` file. Use globs to avoid limitations with regular expressions.
-
-For example, swp1.100 and swp2.100 below do not need an entry in the 
-``interfaces`` file::
-
-    auto br-100
-    iface br-100
-        address 10.0.12.2/24
-        address 2001:dad:beef::3/64
-        bridge-ports swp1.100 swp2.100
-        bridge-stp on
-
-
-
-ifupdown Interface Dependencies
-===============================
-
-``ifupdown`` understands interface dependency relationships. When ``ifup`` and
-``ifdown`` are run with all interfaces, they always run with all interfaces
-in dependency order. When run with the interface list on the command line, the
-default behavior is to not run with dependents. But if there are any built-in 
-dependents, they will be brought up or down.
-
-To run with dependents when you specify the interface list, use the 
-``--with-depends`` option. ``--with-depends`` walks through all dependents
-in the dependency tree rooted at the interface you specify. Consider the
-following example configuration::
-
-    auto bond1
-    iface bond1
-        address 100.0.0.2/16
-        bond-slaves swp29 swp30
-        bond-mode 802.3ad
-        bond-miimon 100
-        bond-use-carrier 1
-        bond-lacp-rate 1
-        bond-min-links 1
-        bond-xmit-hash-policy layer3+4
-
-    auto bond2
-    iface bond2
-        address 100.0.0.5/16
-        bond-slaves swp31 swp32
-        bond-mode 802.3ad
-        bond-miimon 100
-        bond-use-carrier 1
-        bond-lacp-rate 1
-        bond-min-links 1
-        bond-xmit-hash-policy layer3+4
-
-    auto br2001
-    iface br2001
-        address 12.0.1.3/24
-        bridge-ports bond1.2001 bond2.2001
-        bridge-stp on
-
-Specifying ``ifup --with-depends br2001`` brings up all dependents: bond1.2001, 
-bond2.2001, bond1, bond2, bond1.2001, bond2.2001, swp29, swp30, swp31, swp32.
-
-Similarly, specifying ``ifdown --with-depends br2001`` brings down all 
-dependents: bond1.2001, bond2.2001, bond1, bond2, bond1.2001, bond2.2001, swp29, 
-swp30, swp31, swp32. 
-
-.. warning:: ``ifdown`` always deletes logical interfaces after bringing them 
-   down. Use the ``--admin-state`` option if you only want to administratively 
-   bring the interface up or down. In terms of the above example, 
-   ``ifdown br2001`` deletes ``br2001``.
-
-To guide you through which interfaces will be brought down and up, use the
-``--print-dependency`` option to get the list of dependents.
-
-Use ``ifup --print-dependency=list -a`` to get the dependency list of all 
-interfaces::
-
-    cumulus@switch:~$ sudo ifup --print-dependency=list -a
-    lo : None
-    eth0 : None
-    bond0 : ['swp25', 'swp26']
-    bond1 : ['swp29', 'swp30']
-    bond2 : ['swp31', 'swp32']
-    br0 : ['bond1', 'bond2']
-    bond1.2000 : ['bond1']
-    bond2.2000 : ['bond2']
-    br2000 : ['bond1.2000', 'bond2.2000']
-    bond1.2001 : ['bond1']
-    bond2.2001 : ['bond2']
-    br2001 : ['bond1.2001', 'bond2.2001']
-    swp40 : None
-    swp25 : None
-    swp26 : None
-    swp29 : None
-    swp30 : None
-    swp31 : None
-    swp32 : None
-
-To print the dependency list of a single interface, use::
-
-    cumulus@switch:~$ sudo ifup --print-dependency=list br2001
-    br2001 : ['bond1.2001', 'bond2.2001']
-    bond1.2001 : ['bond1']
-    bond2.2001 : ['bond2']
-    bond1 : ['swp29', 'swp30']
-    bond2 : ['swp31', 'swp32']
-    swp29 : None
-    swp30 : None
-    swp31 : None
-    swp32 : None
-
-
-To print the dependency information of an interface in ``dot`` format::
-
-    cumulus@switch:~$ sudo ifup --print-dependency=dot br2001
-    /* Generated by GvGen v.0.9 (http://software.inl.fr/trac/wiki/GvGen) */
-    digraph G {
-        compound=true;
-        node1 [label="br2001"];
-        node2 [label="bond1.2001"];
-        node3 [label="bond2.2001"];
-        node4 [label="bond1"];
-        node5 [label="bond2"];
-        node6 [label="swp29"];
-        node7 [label="swp30"];
-        node8 [label="swp31"];
-        node9 [label="swp32"];
-        node1->node2;
-        node1->node3;
-        node2->node4;
-        node3->node5;
-        node4->node6;
-        node4->node7;
-        node5->node8;
-        node5->node9;
-    }
-
-You can use ``dot`` to render the graph on an external system where ``dot`` is
-installed.
-
-.. image:: images/interfaces.png
-
-
-To print the dependency information of the entire ``interfaces`` file::
-
-    cumulus@switch:~$ sudo ifup --print-dependency=dot -a >interfaces_all.dot
-
-.. image:: images/interfaces_all.png
-   :width: 800px
-
-
-.. note: The '--print-dependency' option is available with the ``ifup``, 
-   ``ifdown`` and ``ifquery`` commands.
-
-
-Configuring IP Addresses
-========================
-
-In ``/etc/network/interfaces``, list all IP addresses as shown below under the 
-``iface`` section (see ``man interfaces`` for more information)::
-
-    auto swp1
-    iface swp1
-        address 12.0.0.1/30
-        address 12.0.0.2/30
-
-The address method and address family are not mandatory. They default to 
-``inet``/``inet6`` and ``static`` by default, but ``inet``/``inet6`` **must** be 
-specified if you need to specify ``dhcp`` or ``loopback``.
-
-You can specify both IPv4 and IPv6 addresses under the same ``iface`` section::
-
-    auto swp1
-    iface swp1
-        address 12.0.0.1/30
-        address 12.0.0.2/30
-        address 2001:dee:eeef:2::1/64
-
-Specifying User Commands
-========================
-
-You can specify additional user commands in the ``interfaces`` file. As shown in 
-the example below, the interface stanzas in ``/etc/network/interfaces`` can have 
-a command that runs at pre-up, up, post-up, pre-down, down, and post-down::
-
-    auto swp1
-    iface swp1
-        address 12.0.0.1/30
-        up /sbin/foo bar
-
-Any valid command can be hooked in the sequencing of bringing an interface up or 
-down, although commands should be limited in scope to network-related commands 
-associated with the particular interface.  
-
-For example, it wouldn't make sense to install some Debian package on ``ifup`` 
-of swp1, even though that is technically possible. See ``man interfaces`` for 
-more details.
-
-Sourcing Interface File Snippets
-================================
-
-Sourcing interface files helps organize and manage the ``interfaces(5)`` file. 
-For example::
-
-    cumulus@switch:~$ cat /etc/network/interfaces
-    # The loopback network interface
-    auto lo
-    iface lo inet loopback
-
-    # The primary network interface
-    auto eth0
-    iface eth0 inet dhcp
-
-    source /etc/network/interfaces.d/bond0
-
-
-The contents of the sourced file used above are::
-
-    cumulus@switch:~$ cat /etc/network/interfaces.d/bond0
-    auto bond0
-    iface bond0
-        address 14.0.0.9/30
-        address 2001:ded:beef:2::1/64
-        bond-slaves swp25 swp26
-        bond-mode 802.3ad
-        bond-miimon 100
-        bond-use-carrier 1
-        bond-lacp-rate 1
-        bond-min-links 1
-        bond-xmit-hash-policy layer3+4
-               
-Using Globs for Port Lists
-==========================
-
-Some modules support globs to describe port lists. You can use globs to specify 
-bridge ports and bond slaves::
-
-    auto br0
-    iface br0
-        bridge-ports glob swp1-6.100
-
-    auto br1
-    iface br1
-        bridge-ports glob swp7-9.100  swp11.100 glob swp15-18.100
-
-Using Templates
-===============
-
-``ifupdown2`` supports Mako-style templates. For more information see
-`www.makotemplates.org <http://www.makotemplates.org/>`_. The Mako template 
-engine is run over the ``interfaces`` file before parsing.
-
-Use the template to declare cookie-cutter bridges in the ``interfaces`` file::
-
-    %for v in [11,12]:
-    auto vlan${v}
-    iface vlan${v}
-        address 10.20.${v}.3/24
-        bridge-ports glob swp19-20.${v}
-        bridge-stp on
-    %endfor
-
-
-And use it to declare addresses in the ``interfaces`` file::
-
-    %for i in [1,12]:
-    auto swp${i}
-    iface swp${i}
-        address 10.20.${i}.3/24
-
-
-Using ifquery to Validate and Debug Interface Configurations
-============================================================
-
-You use ``ifquery`` to print parsed ``interfaces`` file entries.
-
-To use ``ifquery`` to pretty print ``iface`` entries from the ``interfaces`` 
-file, run::
-
-    cumulus@switch:~$ sudo ifquery bond0
-    auto bond0
-    iface bond0
-        address 14.0.0.9/30
-        address 2001:ded:beef:2::1/64
-        bond-slaves swp25 swp26
-        bond-mode 802.3ad
-        bond-miimon 100
-        bond-use-carrier 1
-        bond-lacp-rate 1
-        bond-min-links 1
-        bond-xmit-hash-policy layer3+4
-
-.. Use ``ifquery -a`` to pretty print all ``iface`` entries from the 
-   ``interfaces`` file.
-
-Use ``ifquery --check`` to check the current running state of an interface within 
-the ``interfaces`` file. It returns exit code ``0`` or ``1`` if the configuration 
-does not match::
-
-    cumulus@switch:~$ sudo ifquery --check bond0
-    iface bond0
-            bond-mode 802.3ad  (✓)
-            bond-miimon 100  (✓)
-            bond-use-carrier 1  (✓)
-            bond-lacp-rate 1  (✓)
-            bond-min-links 1  (✓)
-            bond-xmit-hash-policy layer3+4  (✓)
-            bond-slaves swp25 swp26  (✓)
-            address 14.0.0.9/30  (✓)
-            address 2001:ded:beef:2::1/64  (✓)
-
-.. note:: ``ifquery --check`` is an experimental feature.
-
-.. Use ``ifquery --check -a`` to check all interfaces.
-
-Use ``ifquery --running`` to print the running state of interfaces in the 
-``interfaces`` file format::
-
-    cumulus@switch:~$ sudo ifquery --running bond0
-    auto bond0
-    iface bond0
-        bond-xmit-hash-policy layer3+4
-        bond-miimon 100
-        bond-lacp-rate 1
-        bond-min-links 1
-        bond-slaves swp25 swp26
-        bond-mode 802.3ad
-        address 14.0.0.9/30
-        address 2001:ded:beef:2::1/64
-
-
-``ifquery --syntax-help`` provides help on all possible attributes supported in 
-the ``interfaces`` file. For complete syntax on the ``interfaces`` file, see 
-``man interfaces`` and ``man ifupdown-addons-interfaces``.
-
-``ifquery`` can dump information in JSON format::
-
-    cumulus@switch:~$ sudo ifquery --format=json bond0
-    {
-        "auto": true, 
-        "config": {
-            "bond-use-carrier": "1", 
-            "bond-xmit-hash-policy": "layer3+4", 
-            "bond-miimon": "100", 
-            "bond-lacp-rate": "1", 
-            "bond-min-links": "1", 
-            "bond-slaves": "swp25 swp26", 
-            "bond-mode": "802.3ad", 
-            "address": [
-                "14.0.0.9/30",
-                "2001:ded:beef:2::1/64"
-            ]
-        }, 
-        "addr_method": null, 
-        "name": "bond0", 
-        "addr_family": null
-    }
-
-.. By default ``ifquery`` outputs information in the ``interfaces`` format. Some 
-   options do take the ``--format`` option and can output in JSON format.
-
-
-Useful Links
-============
-
-* `<http://wiki.debian.org/NetworkConfiguration>`_
-* `<http://www.linuxfoundation.org/collaborate/workgroups/networking/bonding>`_
-* `<http://www.linuxfoundation.org/collaborate/workgroups/networking/bridge>`_
-* `<http://www.linuxfoundation.org/collaborate/workgroups/networking/vlan>`_
-
-.. Caveats and Errata
-.. ==================
-
diff --git a/ifupdown2/ifupdown/__init__.py b/ifupdown2/ifupdown/__init__.py
deleted file mode 100644 (file)
index 5f7d90a..0000000
+++ /dev/null
@@ -1,5 +0,0 @@
-""" ifupdown2 package.
-
-.. moduleauthor:: Roopa Prabhu <roopa@cumulusnetworks.com>
-
-"""
diff --git a/ifupdown2/ifupdown/exceptions.py b/ifupdown2/ifupdown/exceptions.py
deleted file mode 100644 (file)
index f6cc8b7..0000000
+++ /dev/null
@@ -1,23 +0,0 @@
-#!/usr/bin/python
-#
-# Copyright 2014 Cumulus Networks, Inc. All rights reserved.
-# Author: Roopa Prabhu, roopa@cumulusnetworks.com
-#
-# ifupdown --
-#    exceptions
-#
-
-class Error(Exception):
-    """Base class for exceptions in ifupdown"""
-
-    pass
-
-class ifaceNotFoundError(Error):
-    pass
-
-
-class invalidValueError(Error):
-    pass
-
-class errorReadingStateError(Error):
-    pass
diff --git a/ifupdown2/ifupdown/graph.py b/ifupdown2/ifupdown/graph.py
deleted file mode 100644 (file)
index 49b1348..0000000
+++ /dev/null
@@ -1,89 +0,0 @@
-#!/usr/bin/python
-#
-# Copyright 2014 Cumulus Networks, Inc. All rights reserved.
-# Author: Roopa Prabhu, roopa@cumulusnetworks.com
-#
-# graph --
-#    graph helper module for ifupdown
-#
-
-import logging
-import copy
-from collections import deque
-try:
-    from gvgen import *
-except ImportError, e:
-    pass
-
-class graph():
-    """ graph functions to sort and print interface graph """
-
-    def __init__(self):
-        self.logger = logging.getLogger('ifupdown.' +
-                    self.__class__.__name__)
-
-    @classmethod
-    def topological_sort_graphs_all(cls, dependency_graphs, indegrees_arg):
-        """ runs topological sort on interface list passed as dependency graph
-
-        Args:
-            **dependency_graphs** (dict): dependency graph with dependency
-                                          lists for interfaces 
-
-            **indegrees_arg** (dict): indegrees array for all interfaces
-        """
-        S = []
-        Q = deque()
-
-        indegrees = copy.deepcopy(indegrees_arg)
-        for ifname,indegree in indegrees.items():
-            if indegree == 0:
-                Q.append(ifname)
-
-        while len(Q):
-            # initialize queue
-            x = Q.popleft()
-
-            # Get dependents of x
-            dlist = dependency_graphs.get(x)
-            if not dlist:
-                S.append(x)
-                continue
-
-            for y in dlist:
-                indegrees[y] = indegrees.get(y) - 1
-                if indegrees.get(y) == 0:
-                    Q.append(y)
-
-            S.append(x)
-
-        for ifname,indegree in indegrees.items():
-            if indegree != 0:
-                raise Exception('cycle found involving iface %s' %ifname +
-                                ' (indegree %d)' %indegree)
-
-        return S
-
-    @classmethod
-    def generate_dots(cls, dependency_graph, indegrees):
-        """ spits out interface dependency graph in dot format
-
-        Args:
-            **dependency_graphs** (dict): dependency graph with dependency
-                                          lists for interfaces 
-
-            **indegrees_arg** (dict): indegrees array for all interfaces
-        """
-
-        gvgraph = GvGen()
-        graphnodes = {}
-        for v in dependency_graph.keys():
-            graphnodes[v] = gvgraph.newItem(v)
-
-        for i, v in graphnodes.items():
-            dlist = dependency_graph.get(i, [])
-            if not dlist:
-                continue
-            for d in dlist:
-                gvgraph.newLink(v, graphnodes.get(d))
-        gvgraph.dot()
diff --git a/ifupdown2/ifupdown/iface.py b/ifupdown2/ifupdown/iface.py
deleted file mode 100644 (file)
index 52e8476..0000000
+++ /dev/null
@@ -1,593 +0,0 @@
-#!/usr/bin/python
-#
-# Copyright 2014 Cumulus Networks, Inc. All rights reserved.
-# Author: Roopa Prabhu, roopa@cumulusnetworks.com
-#
-# iface --
-#    interface object
-#
-
-"""ifupdown2 network interface object
-
-It is modeled based on the 'iface' section in /etc/network/interfaces
-file. But can be extended to include any other network interface format
-"""
-
-from collections import OrderedDict
-import logging
-import json
-
-class ifaceType():
-    UNKNOWN = 0x0
-    IFACE = 0x1
-    BRIDGE_VLAN = 0x2
-
-
-class ifaceRole():
-    """ ifaceRole is used to classify the ifaceobj.role of
-        MASTER or SLAVE where there is a bond or bridge
-        with bond-slaves or bridge-ports.  A bond in a bridge
-        is both a master and slave (0x3)
-    """
-    UNKNOWN = 0x0
-    SLAVE = 0x1
-    MASTER = 0x2
-
-class ifaceLinkKind():
-    """ ifaceLlinkKind is used to identify interfaces
-        in the ifaceobj.link_kind attribute. Dependents of the bridge or
-        bond have an ifaceobj.role attribute of SLAVE and the bridge or
-        bond itself has ifaceobj.role of MASTER.
-    """
-    UNKNOWN = 0x0
-    BRIDGE = 0x1
-    BOND = 0x2
-    VLAN = 0x4
-    VXLAN = 0x8
-
-class ifaceLinkType():
-    LINK_UNKNOWN = 0x0
-    LINK_SLAVE = 0x1
-    LINK_MASTER = 0x2
-    LINK_NA = 0x3
-
-class ifaceDependencyType():
-    """ Indicates type of dependency.
-
-        This class enumerates types of dependency relationships
-        between interfaces.
-
-        iface dependency relationships can be classified
-        into:
-         - link
-         - master/slave
-
-        In a 'link' dependency relationship, dependency can be shared
-        between interfaces. example: swp1.100 and
-        swp1.200 can both have 'link' swp1. swp1 is also a dependency
-        of swp1.100 and swp1.200. As you can see dependency
-        swp1 is shared between swp1.100 and swp1.200.
-         
-        In a master/slave relationship like bridge and
-        its ports: eg: bridge br0 and its ports swp1 and swp2.
-        dependency swp1 and swp2 cannot be shared with any other
-        interface with the same dependency relationship.
-        ie, swp1 and swp2 cannot be in a slave relationship
-        with another interface. Understanding the dependency type is
-        required for any semantic checks between dependencies.
-
-    """
-    UNKNOWN = 0x0
-    LINK = 0x1
-    MASTER_SLAVE = 0x2
-
-class ifaceStatus():
-    """Enumerates iface status """
-
-    UNKNOWN = 0x1
-    SUCCESS = 0x2
-    ERROR = 0x3
-    NOTFOUND = 0x4
-
-    @classmethod
-    def to_str(cls, state):
-        if state == cls.UNKNOWN:
-            return 'unknown'
-        elif state == cls.SUCCESS:
-            return 'success'
-        elif state == cls.ERROR:
-            return 'error'
-        elif state == cls.NOTFOUND:
-            return 'notfound'
-    
-    @classmethod
-    def from_str(cls, state_str):
-        if state_str == 'unknown':
-            return cls.UNKNOWN
-        elif state_str == 'success':
-            return cls.SUCCESS
-        elif state_str == 'error':
-            return cls.ERROR
-
-class ifaceState():
-    """Enumerates iface state """
-
-    UNKNOWN = 0x1
-    NEW = 0x2
-    PRE_UP = 0x3
-    UP = 0x4
-    POST_UP = 0x5
-    PRE_DOWN = 0x6
-    DOWN = 0x7
-    POST_DOWN = 0x8
-
-    # Pseudo states
-    QUERY_CHECKCURR = 0x9
-    QUERY_RUNNING = 0xa
-
-    @classmethod
-    def to_str(cls, state):
-        if state == cls.UNKNOWN:
-            return 'unknown'
-        elif state == cls.NEW:
-            return 'new'
-        elif state == cls.PRE_UP:
-            return 'pre-up'
-        elif state == cls.UP:
-            return 'up'
-        elif state == cls.POST_UP:
-            return 'post-up'
-        elif state == cls.PRE_DOWN:
-            return 'pre-down'
-        elif state == cls.DOWN:
-            return 'down'
-        elif state == cls.POST_DOWN:
-            return 'post-down'
-        elif state == cls.QUERY_CHECKCURR:
-            return 'query-checkcurr'
-        elif state == cls.QUERY_RUNNING:
-            return 'query-running'
-
-    @classmethod
-    def from_str(cls, state_str):
-        if state_str == 'unknown':
-            return cls.UNKNOWN
-        elif state_str == 'new':
-            return cls.NEW
-        elif state_str == 'pre-up':
-            return cls.PRE_UP
-        elif state_str == 'up':
-            return cls.UP
-        elif state_str == 'post-up':
-            return cls.POST_UP
-        elif state_str == 'pre-down':
-            return cls.PRE_DOWN
-        elif state_str == 'down':
-            return cls.DOWN
-        elif state_str == 'post-down':
-            return cls.POST_DOWN
-        elif state_str == 'query-checkcurr':
-            return cls.QUERY_CHECKCURR
-        elif state_str == 'query-running':
-            return cls.QUERY_RUNNING
-
-class ifaceJsonEncoder(json.JSONEncoder):
-    def default(self, o):
-        retconfig = {}
-        if o.config:
-            retconfig = dict((k, (v[0] if len(v) == 1 else v))
-                             for k,v in o.config.items())
-        return OrderedDict({'name' : o.name,
-                            'addr_method' : o.addr_method,
-                            'addr_family' : o.addr_family,
-                            'auto' : o.auto,
-                            'config' : retconfig})
-
-class ifaceJsonDecoder():
-    @classmethod
-    def json_to_ifaceobj(cls, ifaceattrdict):
-        ifaceattrdict['config'] = OrderedDict([(k, (v if isinstance(v, list)
-                                                else [v]))
-                                for k,v in ifaceattrdict.get('config',
-                                            OrderedDict()).items()])
-        return iface(attrsdict=ifaceattrdict)
-
-class iface():
-    """ ifupdown2 iface object class
-    
-    Attributes:
-        **name**      Name of the interface 
-
-        **addr_family**     Address family eg, inet, inet6. Can be None to
-                            indicate both address families
-
-        **addr_method**     Address method eg, static, manual or None for
-                            static address method
-
-        **config**          dictionary of config lines for this interface
-
-        **state**           Configuration state of an interface as defined by
-                            ifaceState
-
-        **status**          Configuration status of an interface as defined by
-                            ifaceStatus
-
-        **flags**           Internal flags used by iface processing
-
-        **priv_flags**      private flags owned by module using this class
-
-        **module_flags**    module flags owned by module using this class
-
-        **refcnt**          reference count, indicating number of interfaces
-                            dependent on this iface
-
-        **lowerifaces**     list of interface names lower to this interface or
-                            this interface depends on
-
-        **upperifaces**     list of interface names upper to this interface or
-                            the interfaces that depend on this interface 
-
-        **auto**            True if interface belongs to the auto class
-
-        **classes**         List of classes the interface belongs to
-
-        **env**             shell environment the interface needs during
-                            execution
-
-        **raw_config**      raw interface config from file
-    """
-
-    # flag to indicate that the object was created from pickled state
-    _PICKLED = 0x00000001
-    HAS_SIBLINGS = 0x00000010
-    IFACERANGE_ENTRY = 0x00000100
-    IFACERANGE_START = 0x00001000
-
-    version = '0.1'
-
-    def __init__(self, attrsdict={}):
-        self._set_attrs_from_dict(attrsdict)
-        self._config_status = {}
-        """dict with config status of iface attributes"""
-        self.state = ifaceState.NEW
-        """iface state (of type ifaceState) """
-        self.status = ifaceStatus.UNKNOWN
-        """iface status (of type ifaceStatus) """
-        self.status_str = None
-        """iface status str (string representing the status) """
-        self.flags = 0x0
-        """iface flags """
-        self.priv_flags = 0x0
-        """iface module flags dictionary with module name: flags"""
-        self.module_flags = {}
-        """iface priv flags. can be used by the external object manager """
-        self.refcnt = 0
-        """iface refcnt (incremented for each dependent this interface has) """
-        self.lowerifaces = None 
-        """lower iface list (in other words: slaves of this interface """
-        self.upperifaces = None
-        """upper iface list (in other words: master of this interface """
-        self.classes = []
-        """interface classes this iface belongs to """
-        self.env = None
-        """environment variable dict required for this interface to run"""
-        self.raw_config = []
-        """interface config/attributes in raw format (eg: as it appeared in the interfaces file)"""
-        self.linkstate = None
-        """linkstate of the interface"""
-        self.type = ifaceType.UNKNOWN
-        """interface type"""
-        self.priv_data = None
-        self.role = ifaceRole.UNKNOWN
-        self.realname = None
-        self.link_type = ifaceLinkType.LINK_UNKNOWN
-        self.link_kind = ifaceLinkKind.UNKNOWN
-
-        # The below attribute is used to disambiguate between various
-        # types of dependencies
-        self.dependency_type = ifaceDependencyType.UNKNOWN
-
-    def _set_attrs_from_dict(self, attrdict):
-        self.auto = attrdict.get('auto', False)
-        self.name = attrdict.get('name')
-        self.addr_family = attrdict.get('addr_family')
-        self.addr_method = attrdict.get('addr_method')
-        self.config = attrdict.get('config', OrderedDict())
-
-    def inc_refcnt(self):
-        """ increment refcnt of the interface. Usually used to indicate that
-        it has dependents """
-        self.refcnt += 1
-
-    def dec_refcnt(self):
-        """ decrement refcnt of the interface. Usually used to indicate that
-        it has lost its dependent """
-        self.refcnt -= 1
-
-    def is_config_present(self):
-        """ returns true if the interface has user provided config,
-        false otherwise """
-        addr_method = self.addr_method
-        if addr_method and addr_method in ['dhcp', 'dhcp6', 'loopback']:
-            return True
-        if not self.config:
-            return False
-        else:
-            return True
-
-    def set_class(self, classname):
-        """ appends class to the interfaces class list """
-        self.classes.append(classname)
-
-    def set_state_n_status(self, state, status):
-        """ sets state and status of an interface """
-        self.state = state
-        self.status = status
-
-    def set_flag(self, flag):
-        self.flags |= flag
-
-    def clear_flag(self, flag):
-        self.flags &= ~flag
-
-    def add_to_upperifaces(self, upperifacename):
-        """ add to the list of upperifaces """
-        if self.upperifaces:
-            if upperifacename not in self.upperifaces:
-                self.upperifaces.append(upperifacename)
-        else:
-            self.upperifaces = [upperifacename]
-
-    def get_attr_value(self, attr_name):
-        """ add to the list of upperifaces """
-        return self.config.get(attr_name)
-    
-    def get_attr_value_first(self, attr_name):
-        """ get first value of the specified attr name """
-        attr_value_list = self.config.get(attr_name)
-        if attr_value_list:
-            return attr_value_list[0]
-        return None
-
-    def get_attrs_value_first(self, attrs):
-        """ get first value of the first attr in the list.
-            Useful when you have multiple attrs representing the
-            same thing.
-        """
-        for attr in attrs:
-            attr_value_list = self.config.get(attr)
-            if attr_value_list:
-                return attr_value_list[0]
-        return None
-
-    def get_attr_value_n(self, attr_name, attr_index):
-        """ get n'th value of the specified attr name """
-        attr_value_list = self.config.get(attr_name)
-        if attr_value_list:
-            try:
-                return attr_value_list[attr_index]
-            except:
-                return None
-        return None
-
-    @property
-    def get_env(self):
-        """ get shell environment variables the interface must execute in """
-        if not self.env:
-            self.generate_env()
-        return self.env
-
-    def generate_env(self):
-        """ generate shell environment variables dict interface must execute
-        in. This is used to support legacy ifupdown scripts
-        """
-        env = {}
-        config = self.config
-        env['IFACE'] = self.name
-        for attr, attr_value in config.items():
-            attr_env_name = 'IF_%s' %attr.upper()
-            env[attr_env_name] = attr_value[0]
-        if env:
-            self.env = env
-
-    def update_config(self, attr_name, attr_value):
-        """ add attribute name and value to the interface config """
-        self.config.setdefault(attr_name, []).append(attr_value)
-
-    def replace_config(self, attr_name, attr_value):
-        """ add attribute name and value to the interface config """
-        self.config[attr_name] = [attr_value]
-
-    def delete_config(self, attr_name):
-        """ add attribute name and value to the interface config """
-        try:
-            del self.config[attr_name]
-        except:
-            pass
-
-    def update_config_dict(self, attrdict):
-        self.config.update(attrdict)
-
-    def update_config_with_status(self, attr_name, attr_value, attr_status=0):
-        """ add attribute name and value to the interface config and also
-        update the config_status dict with status of this attribute config """
-        if not attr_value:
-            attr_value = ''
-        self.config.setdefault(attr_name, []).append(attr_value)
-        self._config_status.setdefault(attr_name, []).append(attr_status)
-        # set global iface state
-        if attr_status == 1:
-            self.status = ifaceStatus.ERROR
-        elif self.status != ifaceStatus.ERROR:
-            # Not already error, mark success
-            self.status = ifaceStatus.SUCCESS
-
-    def check_n_update_config_with_status_many(self, ifaceobjorig, attr_names,
-                                               attr_status=0):
-        # set multiple attribute status to zero
-        # also updates status only if the attribute is present
-        for attr_name in attr_names:
-            if not ifaceobjorig.get_attr_value_first(attr_name):
-               continue
-            self.config.setdefault(attr_name, []).append('')
-            self._config_status.setdefault(attr_name, []).append(attr_status)
-
-    def get_config_attr_status(self, attr_name, idx=0):
-        """ get status of a attribute config on this interface.
-        
-        Looks at the iface _config_status dict"""
-        return self._config_status.get(attr_name, [])[idx]
-
-    def compare(self, dstiface):
-        """ compares iface object with iface object passed as argument
-
-        Returns True if object self is same as dstiface and False otherwise """
-
-        if self.name != dstiface.name: return False
-        if self.type != dstiface.type: return False
-        if self.addr_family != dstiface.addr_family: return False
-        if self.addr_method != dstiface.addr_method: return False
-        if self.auto != dstiface.auto: return False
-        if self.classes != dstiface.classes: return False
-        if len(self.config) != len(dstiface.config):
-            return False
-        if any(True for k in self.config if k not in dstiface.config):
-            return False
-        if any(True for k,v in self.config.items()
-                    if v != dstiface.config.get(k)): return False
-        return True
-
-
-    def __getstate__(self):
-        odict = self.__dict__.copy()
-        del odict['state']
-        del odict['status']
-        del odict['lowerifaces']
-        del odict['upperifaces']
-        del odict['refcnt']
-        del odict['_config_status']
-        del odict['flags']
-        del odict['priv_flags']
-        del odict['module_flags']
-        del odict['raw_config']
-        del odict['linkstate']
-        del odict['env']
-        del odict['link_type']
-        del odict['link_kind']
-        del odict['role']
-        del odict['dependency_type']
-        return odict
-
-    def __setstate__(self, dict):
-        self.__dict__.update(dict)
-        self._config_status = {}
-        self.state = ifaceState.NEW
-        self.status = ifaceStatus.UNKNOWN
-        self.refcnt = 0
-        self.flags = 0
-        self.lowerifaces = None
-        self.upperifaces = None
-        self.linkstate = None
-        self.env = None
-        self.role = ifaceRole.UNKNOWN
-        self.priv_flags = 0
-        self.module_flags = {}
-        self.raw_config = []
-        self.flags |= self._PICKLED
-        self.link_type = ifaceLinkType.LINK_NA
-        self.link_kind = ifaceLinkKind.UNKNOWN
-        self.dependency_type = ifaceDependencyType.UNKNOWN
-
-    def dump_raw(self, logger):
-        indent = '  '
-        if self.auto:
-            print 'auto %s' %self.name
-        print (self.raw_config[0])
-        for i in range(1, len(self.raw_config)):
-            print(indent + self.raw_config[i])
-        
-    def dump(self, logger):
-        indent = '\t'
-        logger.info(self.name + ' : {')
-        logger.info(indent + 'family: %s' %self.addr_family)
-        logger.info(indent + 'method: %s' %self.addr_method)
-        logger.info(indent + 'flags: %x' %self.flags)
-        logger.info(indent + 'state: %s'
-                %ifaceState.to_str(self.state))
-        logger.info(indent + 'status: %s'
-                %ifaceStatus.to_str(self.status))
-        logger.info(indent + 'refcnt: %d' %self.refcnt)
-        d = self.lowerifaces
-        if d:
-            logger.info(indent + 'lowerdevs: %s' %str(d))
-        else:
-            logger.info(indent + 'lowerdevs: None')
-
-        logger.info(indent + 'config: ')
-        config = self.config
-        if config:
-            logger.info(indent + indent + str(config))
-        logger.info('}')
-
-    def dump_pretty(self, with_status=False,
-                    successstr='success', errorstr='error',
-                    unknownstr='unknown', use_realname=False):
-        indent = '\t'
-        outbuf = ''
-        if use_realname and self.realname:
-            name = '%s' %self.realname
-        else:
-            name = '%s' %self.name
-        if self.auto:
-            outbuf += 'auto %s\n' %name
-        ifaceline = ''
-        if self.type == ifaceType.BRIDGE_VLAN:
-            ifaceline += 'vlan %s' %name
-        else:
-            ifaceline += 'iface %s' %name
-        if self.addr_family:
-            ifaceline += ' %s' %self.addr_family
-        if self.addr_method:
-            ifaceline += ' %s' %self.addr_method
-        if with_status:
-            status_str = None
-            if (self.status == ifaceStatus.ERROR or
-                    self.status == ifaceStatus.NOTFOUND):
-                if self.status_str:
-                    ifaceline += ' (%s)' %self.status_str
-                status_str = errorstr
-            elif self.status == ifaceStatus.SUCCESS:
-                status_str = successstr
-            if status_str:
-               outbuf += '{0:65} {1:>8}'.format(ifaceline, status_str) + '\n'
-            else:
-                outbuf += ifaceline + '\n'
-            if self.status == ifaceStatus.NOTFOUND:
-                outbuf = (outbuf.encode('utf8')
-                    if isinstance(outbuf, unicode) else outbuf)
-                print outbuf + '\n'
-                return
-        else:
-            outbuf += ifaceline + '\n'
-        config = self.config
-        if config:
-            for cname, cvaluelist in config.items():
-                idx = 0
-                for cv in cvaluelist:
-                    if with_status:
-                        s = self.get_config_attr_status(cname, idx)
-                        if s == -1:
-                            status_str = unknownstr
-                        elif s == 1:
-                            status_str = errorstr
-                        elif s == 0:
-                            status_str = successstr
-                        outbuf += (indent + '{0:55} {1:>10}'.format(
-                                   '%s %s' %(cname, cv), status_str)) + '\n'
-                    else:
-                        outbuf += indent + '%s %s\n' %(cname, cv)
-                    idx += 1
-        if with_status:
-            outbuf = (outbuf.encode('utf8')
-                        if isinstance(outbuf, unicode) else outbuf)
-        print outbuf
diff --git a/ifupdown2/ifupdown/iff.py b/ifupdown2/ifupdown/iff.py
deleted file mode 100644 (file)
index f191883..0000000
+++ /dev/null
@@ -1,36 +0,0 @@
-#!/usr/bin/env python
-#
-# Copyright 2014 Cumulus Networks, Inc. All rights reserved.
-#
-# Author: Scott Feldman, sfeldma@cumulusnetworks.com
-#
-#
-# from /usr/include/linux/if.h
-#
-
-# Standard interface flags (netdevice->flags).
-
-IFF_UP = 0x1                  # interface is up
-IFF_BROADCAST = 0x2           # broadcast address valid
-IFF_DEBUG = 0x4               # turn on debugging
-IFF_LOOPBACK = 0x8            # is a loopback net
-IFF_POINTOPOINT = 0x10        # interface is has p-p link
-IFF_NOTRAILERS = 0x20         # avoid use of trailers
-IFF_RUNNING = 0x40            # interface RFC2863 OPER_UP
-IFF_NOARP = 0x80              # no ARP protocol
-IFF_PROMISC = 0x100           # receive all packets
-IFF_ALLMULTI = 0x200          # receive all multicast packets
-
-IFF_MASTER = 0x400            # master of a load balancer
-IFF_SLAVE = 0x800             # slave of a load balancer
-
-IFF_MULTICAST = 0x1000        # Supports multicast
-
-IFF_PORTSEL = 0x2000          # can set media type
-IFF_AUTOMEDIA = 0x4000        # auto media select active
-IFF_DYNAMIC = 0x8000          # dialup device with changing addresses
-
-IFF_LOWER_UP = 0x10000        # driver signals L1 up
-IFF_DORMANT = 0x20000         # driver signals dormant
-
-IFF_ECHO = 0x40000            # echo sent packets
diff --git a/ifupdown2/ifupdown/ifupdownbase.py b/ifupdown2/ifupdown/ifupdownbase.py
deleted file mode 100644 (file)
index 2a6b480..0000000
+++ /dev/null
@@ -1,72 +0,0 @@
-#!/usr/bin/python
-#
-# Copyright 2014 Cumulus Networks, Inc. All rights reserved.
-# Author: Roopa Prabhu, roopa@cumulusnetworks.com
-#
-# ifupdownBase --
-#    base object for various ifupdown objects
-#
-
-import logging
-import subprocess
-import re
-import os
-from iface import *
-import rtnetlink_api as rtnetlink_api
-
-class ifupdownBase(object):
-
-    def __init__(self):
-        modulename = self.__class__.__name__
-        self.logger = logging.getLogger('ifupdown.' + modulename)
-
-    def exec_command(self, cmd, cmdenv=None, nowait=False):
-        cmd_returncode = 0
-        cmdout = ''
-        try:
-            self.logger.info('Executing ' + cmd)
-            if self.DRYRUN:
-                return cmdout
-            ch = subprocess.Popen(cmd.split(),
-                    stdout=subprocess.PIPE,
-                    shell=False, env=cmdenv,
-                    stderr=subprocess.STDOUT,
-                    close_fds=True)
-            cmdout = ch.communicate()[0]
-            cmd_returncode = ch.wait()
-        except OSError, e:
-            raise Exception('could not execute ' + cmd +
-                    '(' + str(e) + ')')
-        if cmd_returncode != 0:
-            raise Exception('error executing cmd \'%s\'' %cmd +
-                '\n(' + cmdout.strip('\n ') + ')')
-        return cmdout
-
-    def ignore_error(self, errmsg):
-        if (self.FORCE == True or re.search(r'exists', errmsg,
-            re.IGNORECASE | re.MULTILINE) is not None):
-            return True
-        return False
-
-    def log_warn(self, str):
-        if self.ignore_error(str) == False:
-            if self.logger.getEffectiveLevel() == logging.DEBUG:
-                traceback.print_stack()
-            self.logger.warn(str)
-        pass
-
-    def log_error(self, str):
-        if self.ignore_error(str) == False:
-            raise
-            #raise Exception(str)
-        else:
-            pass
-
-    def link_exists(self, ifacename):
-        return os.path.exists('/sys/class/net/%s' %ifacename)
-
-    def link_up(self, ifacename):
-        rtnetlink_api.rtnl_api.link_set(ifacename, "up")
-
-    def link_down(self, ifacename):
-        rtnetlink_api.rtnl_api.link_set(ifacename, "down")
diff --git a/ifupdown2/ifupdown/ifupdownmain.py b/ifupdown2/ifupdown/ifupdownmain.py
deleted file mode 100644 (file)
index 549dd50..0000000
+++ /dev/null
@@ -1,1403 +0,0 @@
-#!/usr/bin/python
-#
-# Copyright 2014 Cumulus Networks, Inc. All rights reserved.
-# Author: Roopa Prabhu, roopa@cumulusnetworks.com
-#
-# ifupdownMain --
-#    ifupdown main module
-#
-
-import os
-import re
-import imp
-import pprint
-import logging
-import sys, traceback
-import copy
-import json
-from statemanager import *
-from networkinterfaces import *
-from iface import *
-from scheduler import *
-from collections import deque
-from collections import OrderedDict
-from graph import *
-from sets import Set
-
-"""
-.. module:: ifupdownmain
-:synopsis: main module for ifupdown package
-
-.. moduleauthor:: Roopa Prabhu <roopa@cumulusnetworks.com>
-
-"""
-
-_tickmark = u'\u2713'
-_crossmark = u'\u2717'
-_success_sym = '(%s)' %_tickmark
-_error_sym = '(%s)' %_crossmark
-
-class ifupdownFlags():
-    FORCE = False
-    DRYRUN = False
-    NOWAIT = False
-    PERFMODE = False
-    CACHE = False
-
-    # Flags
-    CACHE_FLAGS = 0x0
-
-class ifupdownMain(ifupdownBase):
-    """ ifupdown2 main class """
-
-    # Flags
-    WITH_DEPENDS = False
-    ALL = False
-    IFACE_CLASS = False
-    COMPAT_EXEC_SCRIPTS = False
-    STATEMANAGER_ENABLE = True
-    STATEMANAGER_UPDATE = True
-    ADDONS_ENABLE = False
-
-    # priv flags to mark iface objects
-    BUILTIN = 0x0001
-    NOCONFIG = 0x0010
-
-    scripts_dir='/etc/network'
-    addon_modules_dir='/usr/share/ifupdownaddons'
-    addon_modules_configfile='/var/lib/ifupdownaddons/addons.conf'
-
-    # iface dictionary in the below format:
-    # { '<ifacename>' : [<ifaceobject1>, <ifaceobject2> ..] }
-    # eg:
-    # { 'swp1' : [<iface swp1>, <iface swp2> ..] }
-    #
-    # Each ifaceobject corresponds to a configuration block for
-    # that interface
-    # The value in the dictionary is a list because the network
-    # interface configuration file supports more than one iface section
-    # in the interfaces file
-    ifaceobjdict = OrderedDict()
-
-    # iface dictionary representing the curr running state of an iface
-    # in the below format:
-    # {'<ifacename>' : <ifaceobject>}
-    ifaceobjcurrdict = OrderedDict()
-
-    # Dictionary representing operation and modules
-    # for every operation
-    module_ops = OrderedDict([('pre-up', []),
-                              ('up' , []),
-                              ('post-up' , []),
-                              ('query-checkcurr', []),
-                              ('query-running', []),
-                              ('query-dependency', []),
-                              ('query', []),
-                              ('query-raw', []),
-                              ('pre-down', []),
-                              ('down' , []),
-                              ('post-down' , [])])
-
-    # For old style /etc/network/ bash scripts
-    script_ops = OrderedDict([('pre-up', []),
-                                    ('up' , []),
-                                    ('post-up' , []),
-                                    ('pre-down', []),
-                                    ('down' , []),
-                                    ('post-down' , [])])
-
-    # Handlers for ops that ifupdown2 owns
-    def run_up(self, ifaceobj):
-        # Skip link sets on ifaceobjs of type 'vlan' (used for l2 attrs).
-        # there is no real interface behind it
-        if ifaceobj.type == ifaceType.BRIDGE_VLAN:
-            return
-        if (ifaceobj.addr_method and
-            ifaceobj.addr_method == 'manual'):
-            return
-        if self._delay_admin_state:
-            self._delay_admin_state_iface_queue.append(ifaceobj.name)
-            return
-        # If this object is a link slave, ie its link is controlled
-        # by its link master interface, then dont set the link state.
-        # But do allow user to change state of the link if the interface
-        # is already with its link master (hence the master check).
-        if ifaceobj.link_type == ifaceLinkType.LINK_SLAVE:
-            return
-        if not self.link_exists(ifaceobj.name):
-           return
-        self.link_up(ifaceobj.name)
-
-    def run_down(self, ifaceobj):
-        # Skip link sets on ifaceobjs of type 'vlan' (used for l2 attrs)
-        # there is no real interface behind it
-        if ifaceobj.type == ifaceType.BRIDGE_VLAN:
-            return
-        if (ifaceobj.addr_method and
-            ifaceobj.addr_method == 'manual'):
-            return
-        if self._delay_admin_state:
-            self._delay_admin_state_iface_queue.append(ifaceobj.name)
-            return
-        # If this object is a link slave, ie its link is controlled
-        # by its link master interface, then dont set the link state.
-        # But do allow user to change state of the link if the interface
-        # is already with its link master (hence the master check).
-        if ifaceobj.link_type == ifaceLinkType.LINK_SLAVE:
-           return
-        if not self.link_exists(ifaceobj.name):
-           return
-        self.link_down(ifaceobj.name)
-
-    # ifupdown object interface operation handlers
-    ops_handlers = OrderedDict([('up', run_up),
-                                ('down', run_down)])
-
-    def run_sched_ifaceobj_posthook(self, ifaceobj, op):
-        if ((ifaceobj.priv_flags & self.BUILTIN) or
-            (ifaceobj.priv_flags & self.NOCONFIG)):
-            return
-        if self.STATEMANAGER_UPDATE:
-            self.statemanager.ifaceobj_sync(ifaceobj, op)
-
-    # ifupdown object interface scheduler pre and posthooks
-    sched_hooks = {'posthook' : run_sched_ifaceobj_posthook}
-
-    def __init__(self, config={},
-                 force=False, dryrun=False, nowait=False,
-                 perfmode=False, withdepends=False, njobs=1,
-                 cache=False, addons_enable=True, statemanager_enable=True,
-                 interfacesfile='/etc/network/interfaces',
-                 interfacesfileiobuf=None,
-                 interfacesfileformat='native'):
-        """This member function initializes the ifupdownmain object.
-
-        Kwargs:
-            config (dict):  config dict from /etc/network/ifupdown2/ifupdown2.conf
-            force (bool): force interface configuration
-            dryrun (bool): dryrun interface configuration
-            withdepends (bool): apply interface configuration on all depends
-            interfacesfile (str): interfaces file. default is /etc/network/interfaces
-            interfacesfileformat (str): default is 'native'. Other choices are 'json'
-
-        Raises:
-            AttributeError, KeyError """
-
-        self.logger = logging.getLogger('ifupdown')
-        self.FORCE = force
-        self.DRYRUN = dryrun
-        self.NOWAIT = nowait
-        self.PERFMODE = perfmode
-        self.WITH_DEPENDS = withdepends
-        self.STATEMANAGER_ENABLE = statemanager_enable
-        self.CACHE = cache
-        self.interfacesfile = interfacesfile
-        self.interfacesfileiobuf = interfacesfileiobuf
-        self.interfacesfileformat = interfacesfileformat
-        self.config = config
-        self.logger.debug(self.config)
-
-        self.type = ifaceType.UNKNOWN
-
-        # Can be used to provide hints for caching
-        self.CACHE_FLAGS = 0x0
-        self._DELETE_DEPENDENT_IFACES_WITH_NOCONFIG = False
-        self.ADDONS_ENABLE = addons_enable
-
-        # Copy flags into ifupdownFlags
-        # XXX: before we transition fully to ifupdownFlags
-        ifupdownFlags.FORCE = force
-        ifupdownFlags.DRYRUN = dryrun
-        ifupdownFlags.NOWAIT = nowait
-        ifupdownFlags.PERFMODE = perfmode
-        ifupdownFlags.CACHE = cache
-
-        self.ifaces = OrderedDict()
-        self.njobs = njobs
-        self.pp = pprint.PrettyPrinter(indent=4)
-        self.modules = OrderedDict({})
-        self.module_attrs = {}
-        
-        self.load_addon_modules(self.addon_modules_dir)
-        if self.COMPAT_EXEC_SCRIPTS:
-            self.load_scripts(self.scripts_dir)
-        self.dependency_graph = OrderedDict({})
-
-        self._cache_no_repeats = {}
-
-        if self.STATEMANAGER_ENABLE:
-            try:
-                self.statemanager = stateManager()
-                self.statemanager.read_saved_state()
-            except Exception, e:
-                # XXX Maybe we should continue by ignoring old state
-                self.logger.warning('error reading state (%s)' %str(e))
-                raise
-        else:
-            self.STATEMANAGER_UPDATE = False
-        self._delay_admin_state = True if self.config.get(
-                            'delay_admin_state_change', '0') == '1' else False
-        self._delay_admin_state_iface_queue = []
-        if self._delay_admin_state:
-            self.logger.info('\'delay_admin_state_change\' is set. admin ' +
-                             'state changes will be delayed till the end.')
-
-        self._link_master_slave = True if self.config.get(
-                      'link_master_slave', '0') == '1' else False
-        if self._link_master_slave:
-            self.logger.info('\'link_master_slave\' is set. slave admin ' +
-                             'state changes will be delayed till the ' +
-                             'masters admin state change.')
-
-    def link_master_slave_ignore_error(self, errorstr):
-        # If link master slave flag is set, 
-        # there may be cases where the lowerdev may not be
-        # up resulting in 'Network is down' error
-        # This can happen if the lowerdev is a LINK_SLAVE
-        # of another interface which is not up yet
-        # example of such a case:
-        #   bringing up a vlan on a bond interface and the bond
-        #   is a LINK_SLAVE of a bridge (in other words the bond is
-        #   part of a bridge) which is not up yet
-        if self._link_master_slave:
-           if 'Network is down':
-              return True
-        return False
-
-    def get_ifaceobjs(self, ifacename):
-        return self.ifaceobjdict.get(ifacename)
-
-    def get_ifaceobjs_saved(self, ifacename):
-        """ Return ifaceobjects from statemanager """
-        if self.STATEMANAGER_ENABLE:
-           return self.statemanager.get_ifaceobjs(ifacename)
-        else:
-           None
-
-    def get_ifaceobj_first(self, ifacename):
-        ifaceobjs = self.get_ifaceobjs(ifacename)
-        if ifaceobjs:
-            return ifaceobjs[0]
-        return None
-
-    def get_ifacenames(self):
-        return self.ifaceobjdict.keys()
-
-    def get_iface_obj_last(self, ifacename):
-        return self.ifaceobjdict.get(ifacename)[-1]
-
-
-    def must_follow_upperifaces(self, ifacename):
-        #
-        # XXX: This bleeds the knowledge of iface
-        # types in the infrastructure module.
-        # Cant think of a better fix at the moment.
-        # In future maybe the module can set a flag
-        # to indicate if we should follow upperifaces
-        #
-        ifaceobj = self.get_ifaceobj_first(ifacename)
-        if ifaceobj.type == ifaceType.BRIDGE_VLAN:
-            return False
-        return True
-
-    def create_n_save_ifaceobj(self, ifacename, priv_flags=None,
-                               increfcnt=False):
-        """ creates a iface object and adds it to the iface dictionary """
-        ifaceobj = iface()
-        ifaceobj.name = ifacename
-        ifaceobj.priv_flags = priv_flags
-        ifaceobj.auto = True
-        if not self._link_master_slave:
-            ifaceobj.link_type = ifaceLinkType.LINK_NA
-        if increfcnt:
-            ifaceobj.inc_refcnt()
-        self.ifaceobjdict[ifacename] = [ifaceobj]
-        return ifaceobj
-
-    def create_n_save_ifaceobjcurr(self, ifaceobj):
-        """ creates a copy of iface object and adds it to the iface
-            dict containing current iface objects 
-        """
-        ifaceobjcurr = iface()
-        ifaceobjcurr.name = ifaceobj.name
-        ifaceobjcurr.type = ifaceobj.type
-        ifaceobjcurr.lowerifaces = ifaceobj.lowerifaces
-        ifaceobjcurr.priv_flags = ifaceobj.priv_flags
-        ifaceobjcurr.auto = ifaceobj.auto
-        self.ifaceobjcurrdict.setdefault(ifaceobj.name,
-                                     []).append(ifaceobjcurr)
-        return ifaceobjcurr
-
-    def get_ifaceobjcurr(self, ifacename, idx=0):
-        ifaceobjlist = self.ifaceobjcurrdict.get(ifacename)
-        if not ifaceobjlist:
-            return None
-        if not idx:
-            return ifaceobjlist
-        else:
-            return ifaceobjlist[idx]
-
-    def get_ifaceobjrunning(self, ifacename):
-        return self.ifaceobjrunningdict.get(ifacename)
-
-    def get_iface_refcnt(self, ifacename):
-        """ Return iface ref count """
-        max = 0
-        ifaceobjs = self.get_ifaceobjs(ifacename)
-        if not ifaceobjs:
-            return 0
-        for i in ifaceobjs:
-            if i.refcnt > max:
-                max = i.refcnt
-        return max
-
-    def is_iface_builtin_byname(self, ifacename):
-        """ Returns true if iface name is a builtin interface.
-        
-        A builtin interface is an interface which ifupdown understands.
-        The following are currently considered builtin ifaces:
-            - vlan interfaces in the format <ifacename>.<vlanid>
-        """
-        return '.' in ifacename
-
-    def is_ifaceobj_builtin(self, ifaceobj):
-        """ Returns true if iface name is a builtin interface.
-        
-        A builtin interface is an interface which ifupdown understands.
-        The following are currently considered builtin ifaces:
-            - vlan interfaces in the format <ifacename>.<vlanid>
-        """
-        return (ifaceobj.priv_flags & self.BUILTIN)
-
-    def is_ifaceobj_noconfig(self, ifaceobj):
-        """ Returns true if iface object did not have a user defined config.
-       
-        These interfaces appear only when they are dependents of interfaces
-        which have user defined config
-        """
-        return (ifaceobj.priv_flags & self.NOCONFIG)
-
-    def is_iface_noconfig(self, ifacename):
-        """ Returns true if iface has no config """
-
-        ifaceobj = self.get_ifaceobj_first(ifacename)
-        if not ifaceobj: return True
-        return self.is_ifaceobj_noconfig(ifaceobj)
-
-    def check_shared_dependents(self, ifaceobj, dlist):
-        """ Check if dlist intersects with any other
-            interface with slave dependents.
-            example: bond and bridges.
-            This function logs such errors """
-        setdlist = Set(dlist)
-        for ifacename, ifacedlist in self.dependency_graph.items():
-            if not ifacedlist:
-                continue
-            check_depends = False
-            iobjs = self.get_ifaceobjs(ifacename)
-            for i in iobjs:
-                if (i.dependency_type == ifaceDependencyType.MASTER_SLAVE):
-                    check_depends = True
-            if check_depends:
-                common = Set(ifacedlist).intersection(setdlist)
-                if common:
-                    self.logger.error('misconfig..?. iface %s and %s '
-                            %(ifaceobj.name, ifacename) +
-                            'seem to share dependents/ports %s' %str(list(common)))
-
-    def preprocess_dependency_list(self, upperifaceobj, dlist, ops):
-        """ We go through the dependency list and
-            delete or add interfaces from the interfaces dict by
-            applying the following rules:
-                if flag _DELETE_DEPENDENT_IFACES_WITH_NOCONFIG is True:
-                    we only consider devices whose configuration was
-                    specified in the network interfaces file. We delete
-                    any interface whose config was not specified except
-                    for vlan devices. vlan devices get special treatment.
-                    Even if they are not present they are created and added
-                    to the ifacesdict
-                elif flag _DELETE_DEPENDENT_IFACES_WITH_NOCONFIG is False:
-                    we create objects for all dependent devices that are not
-                    present in the ifacesdict
-        """
-        del_list = []
-
-        if (upperifaceobj.dependency_type ==
-                    ifaceDependencyType.MASTER_SLAVE):
-            self.check_shared_dependents(upperifaceobj, dlist)
-
-        for d in dlist:
-            dilist = self.get_ifaceobjs(d)
-            if not dilist:
-                ni = None
-                if self.is_iface_builtin_byname(d):
-                    ni = self.create_n_save_ifaceobj(d,
-                            self.BUILTIN | self.NOCONFIG, True)
-                elif not self._DELETE_DEPENDENT_IFACES_WITH_NOCONFIG:
-                    ni = self.create_n_save_ifaceobj(d, self.NOCONFIG,
-                            True)
-                else:
-                    del_list.append(d)
-                if ni:
-                    if upperifaceobj.link_kind & \
-                           (ifaceLinkKind.BOND | ifaceLinkKind.BRIDGE):
-                        ni.role |= ifaceRole.SLAVE
-                    ni.add_to_upperifaces(upperifaceobj.name)
-                    if upperifaceobj.link_type == ifaceLinkType.LINK_MASTER:
-                        ni.link_type = ifaceLinkType.LINK_SLAVE
-            else:
-                for di in dilist:
-                    di.inc_refcnt()
-                    di.add_to_upperifaces(upperifaceobj.name)
-                    if upperifaceobj.link_kind & \
-                           (ifaceLinkKind.BOND | ifaceLinkKind.BRIDGE):
-                        di.role |= ifaceRole.SLAVE
-                    if upperifaceobj.link_type == ifaceLinkType.LINK_MASTER:
-                        di.link_type = ifaceLinkType.LINK_SLAVE
-        for d in del_list:
-            dlist.remove(d)
-
-    def query_dependents(self, ifaceobj, ops, ifacenames, type=None):
-        """ Gets iface dependents by calling into respective modules """
-        ret_dlist = []
-
-        # Get dependents for interface by querying respective modules
-        for module in self.modules.values():
-            try:
-                if ops[0] == 'query-running':
-                    if (not hasattr(module,
-                        'get_dependent_ifacenames_running')):
-                        continue
-                    dlist = module.get_dependent_ifacenames_running(ifaceobj)
-                else:
-                    if (not hasattr(module, 'get_dependent_ifacenames')):
-                        continue
-                    dlist = module.get_dependent_ifacenames(ifaceobj,
-                                        ifacenames)
-            except Exception, e:
-                self.logger.warn('%s: error getting dependent interfaces (%s)'
-                        %(ifaceobj.name, str(e)))
-                dlist = None
-                pass
-            if dlist: ret_dlist.extend(dlist)
-        return list(set(ret_dlist))
-
-
-    def populate_dependency_info(self, ops, ifacenames=None):
-        """ recursive function to generate iface dependency info """
-
-        if not ifacenames:
-            ifacenames = self.ifaceobjdict.keys()
-
-        iqueue = deque(ifacenames)
-        while iqueue:
-            i = iqueue.popleft()
-            # Go through all modules and find dependent ifaces
-            dlist = None
-            ifaceobj = self.get_ifaceobj_first(i)
-            if not ifaceobj: 
-                continue
-            dlist = ifaceobj.lowerifaces
-            if not dlist:
-                dlist = self.query_dependents(ifaceobj, ops, ifacenames)
-            else:
-                continue
-            if dlist:
-                self.preprocess_dependency_list(ifaceobj,
-                                                dlist, ops)
-                ifaceobj.lowerifaces = dlist
-                [iqueue.append(d) for d in dlist]
-            if not self.dependency_graph.get(i):
-                self.dependency_graph[i] = dlist
-
-    def _check_config_no_repeats(self, ifaceobj):
-        """ check if object has an attribute that is
-        restricted to a single object in the system.
-        if yes, warn and return """
-        for k,v in self._cache_no_repeats.items():
-            iv = ifaceobj.config.get(k)
-            if iv and iv[0] == v:
-                self.logger.error('ignoring interface %s. ' %ifaceobj.name +
-                        'Only one object with attribute ' +
-                        '\'%s %s\' allowed.' %(k, v))
-                return True
-        for k, v in self.config.get('no_repeats', {}).items():
-            iv = ifaceobj.config.get(k)
-            if iv and iv[0] == v:
-                self._cache_no_repeats[k] = v
-        return False
-
-    def _save_iface(self, ifaceobj):
-        if self._check_config_no_repeats(ifaceobj):
-           return
-        if not self._link_master_slave:
-           ifaceobj.link_type = ifaceLinkType.LINK_NA
-        currentifaceobjlist = self.ifaceobjdict.get(ifaceobj.name)
-        if not currentifaceobjlist:
-           self.ifaceobjdict[ifaceobj.name]= [ifaceobj]
-           return
-        if ifaceobj.compare(currentifaceobjlist[0]):
-            self.logger.warn('duplicate interface %s found' %ifaceobj.name)
-            return
-        if currentifaceobjlist[0].type == ifaceobj.type:
-            currentifaceobjlist[0].flags |= iface.HAS_SIBLINGS
-            ifaceobj.flags |= iface.HAS_SIBLINGS
-        self.ifaceobjdict[ifaceobj.name].append(ifaceobj)
-
-    def _iface_configattr_syntax_checker(self, attrname, attrval):
-        for m, mdict in self.module_attrs.items():
-            if not mdict:
-                continue
-            attrsdict = mdict.get('attrs')
-            try:
-                if attrsdict.get(attrname):
-                    return True
-            except AttributeError:
-                pass
-        return False
-
-    def _ifaceobj_syntax_checker(self, ifaceobj):
-        err = False
-        for attrname, attrvalue in ifaceobj.config.items():
-            found = False
-            for k, v in self.module_attrs.items():
-                if v and v.get('attrs', {}).get(attrname):
-                    found = True
-                    break
-            if not found:
-                err = True
-                self.logger.warn('%s: unsupported attribute \'%s\'' \
-                                 % (ifaceobj.name, attrname))
-                continue
-        return err
-
-    def read_iface_config(self):
-        """ Reads default network interface config /etc/network/interfaces. """
-        nifaces = networkInterfaces(self.interfacesfile,
-                        self.interfacesfileiobuf,
-                        self.interfacesfileformat,
-                        template_engine=self.config.get('template_engine'),
-                template_lookuppath=self.config.get('template_lookuppath'))
-        nifaces.subscribe('iface_found', self._save_iface)
-        nifaces.subscribe('validateifaceattr',
-                          self._iface_configattr_syntax_checker)
-        nifaces.subscribe('validateifaceobj', self._ifaceobj_syntax_checker)
-        nifaces.load()
-
-    def read_old_iface_config(self):
-        """ Reads the saved iface config instead of default iface config.
-        And saved iface config is already read by the statemanager """
-        self.ifaceobjdict = copy.deepcopy(self.statemanager.ifaceobjdict)
-
-    def _load_addon_modules_config(self):
-        """ Load addon modules config file """
-
-        with open(self.addon_modules_configfile, 'r') as f:
-            lines = f.readlines()
-            for l in lines:
-                try:
-                    litems = l.strip(' \n\t\r').split(',')
-                    if not litems or len(litems) < 2:
-                        continue
-                    operation = litems[0]
-                    mname = litems[1]
-                    self.module_ops[operation].append(mname)
-                except Exception, e:
-                    self.logger.warn('error reading line \'%s\'' %(l, str(e)))
-                    continue
-
-    def load_addon_modules(self, modules_dir):
-        """ load python modules from modules_dir
-
-        Default modules_dir is /usr/share/ifupdownmodules
-
-        """
-        self.logger.info('loading builtin modules from %s' %modules_dir)
-        self._load_addon_modules_config()
-        if not modules_dir in sys.path:
-            sys.path.append(modules_dir)
-        try:
-            for op, mlist in self.module_ops.items():
-                for mname in mlist:
-                    if self.modules.get(mname):
-                        continue
-                    mpath = modules_dir + '/' + mname + '.py'
-                    if os.path.exists(mpath):
-                        try:
-                            m = __import__(mname)
-                            mclass = getattr(m, mname)
-                        except:
-                            raise
-                        minstance = mclass(force=self.FORCE,
-                                        dryrun=self.DRYRUN,
-                                        nowait=self.NOWAIT,
-                                        perfmode=self.PERFMODE,
-                                        cache=self.CACHE,
-                                        cacheflags=self.CACHE_FLAGS)
-                        self.modules[mname] = minstance
-                        try:
-                            self.module_attrs[mname] = minstance.get_modinfo()
-                        except:
-                            pass
-        except: 
-            raise
-
-        # Assign all modules to query operations
-        self.module_ops['query-checkcurr'] = self.modules.keys()
-        self.module_ops['query-running'] = self.modules.keys()
-        self.module_ops['query-dependency'] = self.modules.keys()
-        self.module_ops['query'] = self.modules.keys()
-        self.module_ops['query-raw'] = self.modules.keys()
-
-
-    def _modules_help(self):
-        """ Prints addon modules supported syntax """
-
-        indent = '  '
-        for m, mdict in self.module_attrs.items():
-            if not mdict:
-                continue
-            print('%s: %s' %(m, mdict.get('mhelp')))
-            attrdict = mdict.get('attrs')
-            if not attrdict:
-                continue
-            try:
-                for attrname, attrvaldict in attrdict.items():
-                    if attrvaldict.get('compat', False):
-                        continue
-                    print('%s%s' %(indent, attrname))
-                    print('%shelp: %s' %(indent + '  ',
-                          attrvaldict.get('help', '')))
-                    print ('%srequired: %s' %(indent + '  ',
-                            attrvaldict.get('required', False)))
-                    default = attrvaldict.get('default')
-                    if default:
-                        print('%sdefault: %s' %(indent + '  ', default))
-
-                    validrange = attrvaldict.get('validrange')
-                    if validrange:
-                        print('%svalidrange: %s-%s'
-                              %(indent + '  ', validrange[0], validrange[1]))
-
-                    validvals = attrvaldict.get('validvals')
-                    if validvals:
-                        print('%svalidvals: %s'
-                              %(indent + '  ', ','.join(validvals)))
-
-                    examples = attrvaldict.get('example')
-                    if not examples:
-                        continue
-
-                    print '%sexample:' %(indent + '  ')
-                    for e in examples:
-                        print '%s%s' %(indent + '    ', e)
-            except:
-                pass
-            print ''
-            
-    def load_scripts(self, modules_dir):
-        """ loading user modules from /etc/network/.
-
-        Note that previously loaded python modules override modules found
-        under /etc/network if any
-
-        """
-
-        self.logger.info('looking for user scripts under %s' %modules_dir)
-        for op, mlist in self.script_ops.items():
-            msubdir = modules_dir + '/if-%s.d' %op
-            self.logger.info('loading scripts under %s ...' %msubdir)
-            try:
-                module_list = os.listdir(msubdir)
-                for module in module_list:
-                    if  self.modules.get(module) is not None:
-                        continue
-                    self.script_ops[op].append(
-                                    msubdir + '/' + module)
-            except: 
-                # continue reading
-                pass
-
-    def _sched_ifaces(self, ifacenames, ops, skipupperifaces=False,
-                      followdependents=True, sort=False):
-        self.logger.debug('scheduling \'%s\' for %s'
-                          %(str(ops), str(ifacenames)))
-        self._pretty_print_ordered_dict('dependency graph',
-                    self.dependency_graph)
-        return ifaceScheduler.sched_ifaces(self, ifacenames, ops,
-                        dependency_graph=self.dependency_graph,
-                        order=ifaceSchedulerFlags.INORDER
-                            if 'down' in ops[0]
-                                else ifaceSchedulerFlags.POSTORDER,
-                        followdependents=followdependents,
-                        skipupperifaces=skipupperifaces,
-                        sort=True if (sort or self.IFACE_CLASS) else False)
-
-    def _render_ifacename(self, ifacename):
-        new_ifacenames = []
-        vlan_match = re.match("^([\d]+)-([\d]+)", ifacename)
-        if vlan_match:
-            vlan_groups = vlan_match.groups()
-            if vlan_groups[0] and vlan_groups[1]:
-                [new_ifacenames.append('%d' %v)
-                    for v in range(int(vlan_groups[0]),
-                            int(vlan_groups[1])+1)]
-        return new_ifacenames
-
-    def _preprocess_ifacenames(self, ifacenames):
-        """ validates interface list for config existance.
-       
-        returns -1 if one or more interface not found. else, returns 0
-
-        """
-        new_ifacenames = []
-        err_iface = ''
-        for i in ifacenames:
-            ifaceobjs = self.get_ifaceobjs(i)
-            if not ifaceobjs:
-                # if name not available, render interface name and check again
-                rendered_ifacenames = utils.expand_iface_range(i)
-                if rendered_ifacenames:
-                    for ri in rendered_ifacenames:
-                        ifaceobjs = self.get_ifaceobjs(ri)
-                        if not ifaceobjs:
-                            err_iface += ' ' + ri
-                        else:
-                            new_ifacenames.append(ri)
-                else:
-                    err_iface += ' ' + i
-            else:
-                new_ifacenames.append(i)
-        if err_iface:
-            raise Exception('cannot find interfaces:%s' %err_iface)
-        return new_ifacenames 
-
-    def _iface_whitelisted(self, auto, allow_classes, excludepats, ifacename):
-        """ Checks if interface is whitelisted depending on set of parameters.
-
-        interfaces are checked against the allow_classes and auto lists.
-
-        """
-        if excludepats:
-            for e in excludepats:
-                if re.search(e, ifacename):
-                    return False
-        ifaceobjs = self.get_ifaceobjs(ifacename)
-        if not ifaceobjs:
-            self.logger.debug('iface %s' %ifacename + ' not found')
-            return False
-        # We check classes first
-        if allow_classes:
-            for i in ifaceobjs:
-                if i.classes:
-                    common = Set([allow_classes]).intersection(
-                                Set(i.classes))
-                    if common:
-                        return True
-            return False
-        if auto:
-            for i in ifaceobjs:
-                if i.auto:
-                    return True
-            return False
-        return True
-
-    def _compat_conv_op_to_mode(self, op):
-        """ Returns old op name to work with existing scripts """
-        if op == 'pre-up':
-            return 'start'
-        elif op == 'pre-down':
-            return 'stop'
-        else:
-            return op
-
-    def generate_running_env(self, ifaceobj, op):
-        """ Generates a dictionary with env variables required for
-        an interface. Used to support script execution for interfaces.
-        """
-
-        cenv = None
-        iface_env = ifaceobj.env
-        if iface_env:
-            cenv = os.environ
-            if cenv:
-                cenv.update(iface_env)
-            else:
-                cenv = iface_env
-            cenv['MODE'] = self._compat_conv_op_to_mode(op)
-        return cenv
-
-    def _save_state(self):
-        if not self.STATEMANAGER_ENABLE or not self.STATEMANAGER_UPDATE:
-            return
-        try:
-            # Update persistant iface states
-            self.statemanager.save_state()
-        except Exception, e:
-            if self.logger.isEnabledFor(logging.DEBUG):
-                t = sys.exc_info()[2]
-                traceback.print_tb(t)
-                self.logger.warning('error saving state (%s)' %str(e))
-
-    def set_type(self, type):
-        if type == 'iface':
-            self.type = ifaceType.IFACE
-        elif type == 'vlan':
-            self.type = ifaceType.BRIDGE_VLAN
-        else:
-            self.type = ifaceType.UNKNOWN
-
-    def _process_delay_admin_state_queue(self, op):
-        if not self._delay_admin_state_iface_queue:
-           return
-        if op == 'up':
-           func = self.link_up
-        elif op == 'down':
-           func = self.link_down
-        else:
-           return
-        for i in self._delay_admin_state_iface_queue:
-            try:
-                if self.link_exists(i):
-                   func(i)
-            except Exception, e:
-                self.logger.warn(str(e))
-                pass
-
-    def up(self, ops, auto=False, allow_classes=None, ifacenames=None,
-           excludepats=None, printdependency=None, syntaxcheck=False,
-           type=None, skipupperifaces=False):
-        """This brings the interface(s) up
-        
-        Args:
-            ops (list): list of ops to perform on the interface(s).
-            Eg: ['pre-up', 'up', 'post-up'
-
-        Kwargs:
-            auto (bool): act on interfaces marked auto
-            allow_classes (list): act on interfaces belonging to classes in the list
-            ifacenames (list): act on interfaces specified in this list
-            excludepats (list): list of patterns of interfaces to exclude
-            syntaxcheck (bool): only perform syntax check
-        """
-
-        self.set_type(type)
-
-        if allow_classes:
-            self.IFACE_CLASS = True
-        if not self.ADDONS_ENABLE: self.STATEMANAGER_UPDATE = False
-        if auto:
-            self.ALL = True
-            self.WITH_DEPENDS = True
-        try:
-            self.read_iface_config()
-        except Exception:
-            raise
-
-        # If only syntax check was requested, return here
-        if syntaxcheck:
-            return
-
-        if ifacenames:
-            ifacenames = self._preprocess_ifacenames(ifacenames)
-
-        # if iface list not given by user, assume all from config file
-        if not ifacenames: ifacenames = self.ifaceobjdict.keys()
-
-        # filter interfaces based on auto and allow classes
-        filtered_ifacenames = [i for i in ifacenames
-                               if self._iface_whitelisted(auto, allow_classes,
-                                                excludepats, i)]
-        if not filtered_ifacenames:
-            raise Exception('no ifaces found matching given allow lists')
-
-        if printdependency:
-            self.populate_dependency_info(ops, filtered_ifacenames)
-            self.print_dependency(filtered_ifacenames, printdependency)
-            return
-        else:
-            self.populate_dependency_info(ops)
-
-        try:
-            self._sched_ifaces(filtered_ifacenames, ops,
-                    skipupperifaces=skipupperifaces,
-                    followdependents=True if self.WITH_DEPENDS else False)
-        finally:
-            self._process_delay_admin_state_queue('up')
-            if not self.DRYRUN and self.ADDONS_ENABLE:
-                self._save_state()
-
-    def down(self, ops, auto=False, allow_classes=None, ifacenames=None,
-             excludepats=None, printdependency=None, usecurrentconfig=False,
-             type=None):
-        """ down an interface """
-
-        self.set_type(type)
-
-        if allow_classes:
-            self.IFACE_CLASS = True
-        if not self.ADDONS_ENABLE: self.STATEMANAGER_UPDATE = False
-        if auto:
-            self.ALL = True
-            self.WITH_DEPENDS = True
-        # For down we need to look at old state, unless usecurrentconfig
-        # is set
-        if (not usecurrentconfig and self.STATEMANAGER_ENABLE and
-                    self.statemanager.ifaceobjdict):
-            # Since we are using state manager objects,
-            # skip the updating of state manager objects
-            self.logger.debug('Looking at old state ..')
-            self.read_old_iface_config()
-        else:
-            # If no old state available 
-            try:
-                self.read_iface_config()
-            except Exception, e:
-                raise Exception('error reading iface config (%s)' %str(e))
-        if ifacenames:
-            # If iface list is given by the caller, always check if iface
-            # is present
-            try:
-               ifacenames = self._preprocess_ifacenames(ifacenames)
-            except Exception, e:
-               raise Exception('%s' %str(e) +
-                       ' (interface was probably never up ?)')
-
-        # if iface list not given by user, assume all from config file
-        if not ifacenames: ifacenames = self.ifaceobjdict.keys()
-
-        # filter interfaces based on auto and allow classes
-        filtered_ifacenames = [i for i in ifacenames
-                               if self._iface_whitelisted(auto, allow_classes,
-                                                excludepats, i)]
-        if not filtered_ifacenames:
-            raise Exception('no ifaces found matching given allow lists ' +
-                    '(or interfaces were probably never up ?)')
-
-        if printdependency:
-            self.populate_dependency_info(ops, filtered_ifacenames)
-            self.print_dependency(filtered_ifacenames, printdependency)
-            return
-        else:
-            self.populate_dependency_info(ops)
-
-        try:
-            self._sched_ifaces(filtered_ifacenames, ops,
-                    followdependents=True if self.WITH_DEPENDS else False)
-        finally:
-            self._process_delay_admin_state_queue('down')
-            if not self.DRYRUN and self.ADDONS_ENABLE:
-                self._save_state()
-
-    def query(self, ops, auto=False, allow_classes=None, ifacenames=None,
-              excludepats=None, printdependency=None,
-              format='native', type=None):
-        """ query an interface """
-
-        self.set_type(type)
-
-        if allow_classes:
-            self.IFACE_CLASS = True
-        if self.STATEMANAGER_ENABLE and ops[0] == 'query-savedstate':
-            return self.statemanager.dump_pretty(ifacenames)
-        self.STATEMANAGER_UPDATE = False
-        if auto:
-            self.logger.debug('setting flag ALL')
-            self.ALL = True
-            self.WITH_DEPENDS = True
-
-        if ops[0] == 'query-syntax':
-            self._modules_help()
-            return
-        elif ops[0] == 'query-running':
-            # create fake devices to all dependents that dont have config
-            map(lambda i: self.create_n_save_ifaceobj(i, self.NOCONFIG),
-                    ifacenames)
-        else:
-            try:
-                self.read_iface_config()
-            except Exception:
-                raise
-
-        if ifacenames and ops[0] != 'query-running':
-           # If iface list is given, always check if iface is present
-           ifacenames = self._preprocess_ifacenames(ifacenames)
-
-        # if iface list not given by user, assume all from config file
-        if not ifacenames: ifacenames = self.ifaceobjdict.keys()
-
-        # filter interfaces based on auto and allow classes
-        if ops[0] == 'query-running':
-            filtered_ifacenames = ifacenames
-        else:
-            filtered_ifacenames = [i for i in ifacenames
-                if self._iface_whitelisted(auto, allow_classes,
-                        excludepats, i)]
-        if not filtered_ifacenames:
-                raise Exception('no ifaces found matching ' +
-                        'given allow lists')
-
-        self.populate_dependency_info(ops)
-        if ops[0] == 'query-dependency' and printdependency:
-            self.print_dependency(filtered_ifacenames, printdependency)
-            return
-
-        if ops[0] == 'query':
-            return self.print_ifaceobjs_pretty(filtered_ifacenames, format)
-        elif ops[0] == 'query-raw':
-            return self.print_ifaceobjs_raw(filtered_ifacenames)
-
-        self._sched_ifaces(filtered_ifacenames, ops,
-                           followdependents=True if self.WITH_DEPENDS else False)
-
-        if ops[0] == 'query-checkcurr':
-            ret = self.print_ifaceobjscurr_pretty(filtered_ifacenames, format)
-            if ret != 0:
-                # if any of the object has an error, signal that silently
-                raise Exception('')
-        elif ops[0] == 'query-running':
-            self.print_ifaceobjsrunning_pretty(filtered_ifacenames, format)
-            return
-
-    def _reload_currentlyup(self, upops, downops, auto=True, allow=None,
-            ifacenames=None, excludepats=None, usecurrentconfig=False,
-            **extra_args):
-        """ reload currently up interfaces """
-        allow_classes = []
-        new_ifaceobjdict = {}
-
-        # Override auto to true
-        auto = True
-        try:
-            self.read_iface_config()
-        except:
-            raise
-        if not self.ifaceobjdict:
-            self.logger.warn("nothing to reload ..exiting.")
-            return
-        already_up_ifacenames = []
-        # generate dependency graph of interfaces
-        self.populate_dependency_info(upops)
-        if (not usecurrentconfig and self.STATEMANAGER_ENABLE
-                and self.statemanager.ifaceobjdict):
-            already_up_ifacenames = self.statemanager.ifaceobjdict.keys()
-
-        if not ifacenames: ifacenames = self.ifaceobjdict.keys()
-        filtered_ifacenames = [i for i in ifacenames
-                               if self._iface_whitelisted(auto, allow_classes,
-                               excludepats, i)]
-        
-        # Get already up interfaces that still exist in the interfaces file
-        already_up_ifacenames_not_present = Set(
-                        already_up_ifacenames).difference(ifacenames)
-        already_up_ifacenames_still_present = Set(
-                        already_up_ifacenames).difference(
-                        already_up_ifacenames_not_present)
-        interfaces_to_up = Set(already_up_ifacenames_still_present).union(
-                                            filtered_ifacenames)
-
-        if (already_up_ifacenames_not_present and
-                self.config.get('ifreload_currentlyup_down_notpresent') == '1'):
-           self.logger.info('reload: schedule down on interfaces: %s'
-                            %str(already_up_ifacenames_not_present))
-
-           # Save a copy of new iface objects and dependency_graph
-           new_ifaceobjdict = dict(self.ifaceobjdict)
-           new_dependency_graph = dict(self.dependency_graph)
-
-           # old interface config is read into self.ifaceobjdict
-           self.read_old_iface_config()
-
-           # reinitialize dependency graph 
-           self.dependency_graph = OrderedDict({})
-           self.populate_dependency_info(downops,
-                                         already_up_ifacenames_not_present)
-           self._sched_ifaces(already_up_ifacenames_not_present, downops,
-                              followdependents=False, sort=True)
-        else:
-           self.logger.debug('no interfaces to down ..')
-
-        # Now, run 'up' with new config dict
-        # reset statemanager update flag to default
-        if auto:
-            self.ALL = True
-            self.WITH_DEPENDS = True
-        if new_ifaceobjdict:
-            # and now, ifaceobjdict is back to current config
-            self.ifaceobjdict = new_ifaceobjdict
-            self.dependency_graph = new_dependency_graph
-
-        if not self.ifaceobjdict:
-           return
-        self.logger.info('reload: scheduling up on interfaces: %s'
-                         %str(interfaces_to_up))
-        self._sched_ifaces(interfaces_to_up, upops,
-                followdependents=True if self.WITH_DEPENDS else False)
-        if self.DRYRUN:
-            return
-        self._save_state()
-
-    def _reload_default(self, upops, downops, auto=False, allow=None,
-            ifacenames=None, excludepats=None, usecurrentconfig=False,
-            **extra_args):
-        """ reload interface config """
-        allow_classes = []
-        new_ifaceobjdict = {}
-
-        try:
-            self.read_iface_config()
-        except:
-            raise
-
-        if not self.ifaceobjdict:
-            self.logger.warn("nothing to reload ..exiting.")
-            return
-        # generate dependency graph of interfaces
-        self.populate_dependency_info(upops)
-        if (not usecurrentconfig and self.STATEMANAGER_ENABLE
-                and self.statemanager.ifaceobjdict):
-            # Save a copy of new iface objects and dependency_graph
-            new_ifaceobjdict = dict(self.ifaceobjdict)
-            new_dependency_graph = dict(self.dependency_graph)
-
-            # if old state is present, read old state and mark op for 'down'
-            # followed by 'up' aka: reload
-            # old interface config is read into self.ifaceobjdict
-            self.read_old_iface_config()
-            op = 'reload'
-        else:
-            # oldconfig not available, continue with 'up' with new config
-            op = 'up'
-
-        if not ifacenames: ifacenames = self.ifaceobjdict.keys()
-        if op == 'reload' and ifacenames:
-            filtered_ifacenames = [i for i in ifacenames
-                               if self._iface_whitelisted(auto, allow_classes,
-                               excludepats, i)]
-
-            # if config file had 'ifreload_down_changed' variable
-            # set, also look for interfaces that changed to down them
-            down_changed = int(self.config.get('ifreload_down_changed', '1'))
-
-            # Generate the interface down list
-            # Interfaces that go into the down list:
-            #   - interfaces that were present in last config and are not
-            #     present in the new config
-            #   - interfaces that were changed between the last and current
-            #     config
-            ifacedownlist = []
-            for ifname in filtered_ifacenames:
-                lastifaceobjlist = self.ifaceobjdict.get(ifname)
-                objidx = 0
-                # If interface is not present in the new file
-                # append it to the down list
-                newifaceobjlist = new_ifaceobjdict.get(ifname)
-                if not newifaceobjlist:
-                    ifacedownlist.append(ifname)
-                    continue
-                if not down_changed:
-                    continue
-                if len(newifaceobjlist) != len(lastifaceobjlist):
-                    ifacedownlist.append(ifname)
-                    continue
-
-                # If interface has changed between the current file
-                # and the last installed append it to the down list
-                # compare object list
-                for objidx in range(0, len(lastifaceobjlist)):
-                    oldobj = lastifaceobjlist[objidx]
-                    newobj = newifaceobjlist[objidx]
-                    if not newobj.compare(oldobj):
-                        ifacedownlist.append(ifname)
-                        continue
-
-            if ifacedownlist:
-                self.logger.info('reload: scheduling down on interfaces: %s'
-                                  %str(ifacedownlist))
-                # reinitialize dependency graph 
-                self.dependency_graph = OrderedDict({})
-                # Generate dependency info for old config
-                self.populate_dependency_info(downops, ifacedownlist)
-                try:
-                    self._sched_ifaces(ifacedownlist, downops,
-                                       followdependents=False,
-                                       sort=True)
-                except Exception, e:
-                    self.logger.error(str(e))
-                    pass
-                finally:
-                    self._process_delay_admin_state_queue('down')
-            else:
-                self.logger.debug('no interfaces to down ..')
-
-        # Now, run 'up' with new config dict
-        # reset statemanager update flag to default
-        if not new_ifaceobjdict:
-            return
-
-        if auto:
-            self.ALL = True
-            self.WITH_DEPENDS = True
-        # and now, we are back to the current config in ifaceobjdict
-        self.ifaceobjdict = new_ifaceobjdict
-        self.dependency_graph = new_dependency_graph
-        ifacenames = self.ifaceobjdict.keys()
-        filtered_ifacenames = [i for i in ifacenames
-                               if self._iface_whitelisted(auto, allow_classes,
-                               excludepats, i)]
-
-        self.logger.info('reload: scheduling up on interfaces: %s'
-                         %str(filtered_ifacenames))
-        try:
-            self._sched_ifaces(filtered_ifacenames, upops,
-                    followdependents=True if self.WITH_DEPENDS else False)
-        except Exception, e:
-            self.logger.error(str(e))
-            pass
-        finally:
-            self._process_delay_admin_state_queue('up')
-        if self.DRYRUN:
-            return
-        self._save_state()
-
-    def reload(self, *args, **kargs):
-        """ reload interface config """
-        self.logger.debug('reloading interface config ..')
-        if kargs.get('currentlyup', False):
-            self._reload_currentlyup(*args, **kargs)
-        else:
-            self._reload_default(*args, **kargs)
-
-    def _pretty_print_ordered_dict(self, prefix, argdict):
-        outbuf = prefix + ' {\n'
-        for k, vlist in argdict.items():
-            outbuf += '\t%s : %s\n' %(k, str(vlist))
-        self.logger.debug(outbuf + '}')
-
-    def print_dependency(self, ifacenames, format):
-        """ prints iface dependency information """
-
-        if not ifacenames:
-            ifacenames = self.ifaceobjdict.keys()
-        if format == 'list':
-            for k,v in self.dependency_graph.items():
-                print '%s : %s' %(k, str(v))
-        elif format == 'dot':
-            indegrees = {}
-            map(lambda i: indegrees.update({i :
-                self.get_iface_refcnt(i)}),
-                self.dependency_graph.keys())
-            graph.generate_dots(self.dependency_graph, indegrees)
-
-    def print_ifaceobjs_raw(self, ifacenames):
-        """ prints raw lines for ifaces from config file """
-
-        for i in ifacenames:
-            for ifaceobj in self.get_ifaceobjs(i):
-                if (self.is_ifaceobj_builtin(ifaceobj) or 
-                    not ifaceobj.is_config_present()):
-                    continue
-                ifaceobj.dump_raw(self.logger)
-                print '\n'
-                if self.WITH_DEPENDS and not self.ALL:
-                    dlist = ifaceobj.lowerifaces
-                    if not dlist: continue
-                    self.print_ifaceobjs_raw(dlist)
-
-    def _get_ifaceobjs_pretty(self, ifacenames, ifaceobjs, running=False):
-        """ returns iface obj list """
-
-        for i in ifacenames:
-            for ifaceobj in self.get_ifaceobjs(i):
-                if ((not running and self.is_ifaceobj_noconfig(ifaceobj)) or
-                    (running and not ifaceobj.is_config_present())):
-                    continue
-                ifaceobjs.append(ifaceobj)
-                if self.WITH_DEPENDS and not self.ALL:
-                    dlist = ifaceobj.lowerifaces
-                    if not dlist: continue
-                    self._get_ifaceobjs_pretty(dlist, ifaceobjs, running)
-
-    def print_ifaceobjs_pretty(self, ifacenames, format='native'):
-        """ pretty prints iface in format given by keyword arg format """
-
-        ifaceobjs = []
-        self._get_ifaceobjs_pretty(ifacenames, ifaceobjs)
-        if not ifaceobjs: return
-        if format == 'json':
-            print json.dumps(ifaceobjs, cls=ifaceJsonEncoder,
-                             indent=4, separators=(',', ': '))
-        else:
-            expand = int(self.config.get('ifquery_ifacename_expand_range', '0'))
-            for i in ifaceobjs:
-                if not expand and (i.flags & iface.IFACERANGE_ENTRY):
-                    # print only the first one
-                    if i.flags & iface.IFACERANGE_START:
-                       i.dump_pretty(use_realname=True)
-                else:
-                    i.dump_pretty()
-
-    def _get_ifaceobjscurr_pretty(self, ifacenames, ifaceobjs):
-        ret = 0
-        for i in ifacenames:
-            ifaceobjscurr = self.get_ifaceobjcurr(i)
-            if not ifaceobjscurr: continue
-            for ifaceobj in ifaceobjscurr:
-                if (ifaceobj.status == ifaceStatus.NOTFOUND or
-                    ifaceobj.status == ifaceStatus.ERROR):
-                    ret = 1
-                if self.is_ifaceobj_noconfig(ifaceobj):
-                    continue
-                ifaceobjs.append(ifaceobj)
-                if self.WITH_DEPENDS and not self.ALL:
-                    dlist = ifaceobj.lowerifaces
-                    if not dlist: continue
-                    dret = self._get_ifaceobjscurr_pretty(dlist, ifaceobjs)
-                    if dret: ret = 1
-        return ret
-
-    def print_ifaceobjscurr_pretty(self, ifacenames, format='native'):
-        """ pretty prints current running state of interfaces with status.
-
-        returns 1 if any of the interface has an error,
-        else returns 0
-        """
-
-        ifaceobjs = []
-        ret = self._get_ifaceobjscurr_pretty(ifacenames, ifaceobjs)
-        if not ifaceobjs: return
-        if format == 'json':
-            print json.dumps(ifaceobjs, cls=ifaceJsonEncoder, indent=2,
-                       separators=(',', ': '))
-        else:
-            map(lambda i: i.dump_pretty(with_status=True,
-                   successstr=self.config.get('ifquery_check_success_str',
-                                              _success_sym),
-                   errorstr=self.config.get('ifquery_check_error_str', _error_sym),
-                   unknownstr=self.config.get('ifquery_check_unknown_str', '')),
-                   ifaceobjs)
-        return ret
-
-    def print_ifaceobjsrunning_pretty(self, ifacenames, format='native'):
-        """ pretty prints iface running state """
-
-        ifaceobjs = []
-        self._get_ifaceobjs_pretty(ifacenames, ifaceobjs, running=True)
-        if not ifaceobjs: return
-        if format == 'json':
-            print json.dumps(ifaceobjs, cls=ifaceJsonEncoder, indent=2,
-                       separators=(',', ': '))
-        else:
-            map(lambda i: i.dump_pretty(), ifaceobjs)
-
-    def _dump(self):
-        print 'ifupdown main object dump'
-        print self.pp.pprint(self.modules)
-        print self.pp.pprint(self.ifaceobjdict)
-
-    def _dump_ifaceobjs(self, ifacenames):
-        for i in ifacenames:
-            ifaceobjs = self.get_ifaceobjs(i)
-            for i in ifaceobjs:
-                i.dump(self.logger)
-                print '\n'
diff --git a/ifupdown2/ifupdown/netlink.py b/ifupdown2/ifupdown/netlink.py
deleted file mode 100644 (file)
index 5a01043..0000000
+++ /dev/null
@@ -1,241 +0,0 @@
-#!/usr/bin/env python
-#
-# Copyright 2014 Cumulus Networks, Inc. All rights reserved.
-# Author: Scott Feldman, sfeldma@cumulusnetworks.com
-#
-
-from os import strerror
-import select
-from time import time
-import socket
-from ctypes import *
-from errno import *
-import logging
-
-logger = logging.getLogger(__name__)
-
-#
-# from /usr/include/linux/netlink.h
-#
-
-NETLINK_ROUTE = 0            # Routing/device hook
-NETLINK_UNUSED = 1           # Unused number
-NETLINK_USERSOCK = 2         # Reserved for user mode socket protocols 
-NETLINK_FIREWALL = 3         # Firewalling hook
-NETLINK_INET_DIAG = 4        # INET socket monitoring
-NETLINK_NFLOG = 5            # netfilter/iptables ULOG 
-NETLINK_XFRM = 6             # ipsec 
-NETLINK_SELINUX = 7          # SELinux event notifications 
-NETLINK_ISCSI = 8            # Open-iSCSI 
-NETLINK_AUDIT = 9            # auditing 
-NETLINK_FIB_LOOKUP = 10        
-NETLINK_CONNECTOR = 11
-NETLINK_NETFILTER = 12       # netfilter subsystem 
-NETLINK_IP6_FW = 13
-NETLINK_DNRTMSG = 14         # DECnet routing messages 
-NETLINK_KOBJECT_UEVENT = 15  # Kernel messages to userspace 
-NETLINK_GENERIC = 16
-NETLINK_SCSITRANSPORT = 18   # SCSI Transports 
-NETLINK_ECRYPTFS = 19
-NETLINK_RDMA = 20
-NETLINK_CRYPTO = 21          # Crypto layer 
-
-NLMSG_NOOP = 1        # Nothing.
-NLMSG_ERROR = 2       # Error
-NLMSG_DONE = 3        # End of a dump
-NLMSG_OVERRUN = 4     # Data lost
-
-NETLINK_NO_ENOBUFS = 5
-
-SOL_NETLINK = 270
-
-class Nlmsghdr(Structure):
-
-    _fields_ = [
-        ('nlmsg_len', c_uint32),
-        ('nlmsg_type', c_uint16),
-        ('nlmsg_flags', c_uint16),
-        ('nlmsg_seq', c_uint32),
-        ('nlmsg_pid', c_uint32)
-    ]
-
-    def dump(self):
-        print 'nlmsg_len', self.nlmsg_len
-        print 'nlmsg_type', self.nlmsg_type
-        print 'nlmsg_flags 0x%04x' % self.nlmsg_flags
-        print 'nlmsg_seq', self.nlmsg_seq
-        print 'nlmsg_pid', self.nlmsg_pid
-
-# Flags values
-
-NLM_F_REQUEST = 1          # It is request message.
-NLM_F_MULTI = 2            # Multipart message, terminated by NLMSG_DONE
-NLM_F_ACK = 4              # Reply with ack, with zero or error code
-NLM_F_ECHO = 8             # Echo this request
-NLM_F_DUMP_INTR = 16       # Dump was inconsistent due to sequence change
-
-# Modifiers to GET request
-NLM_F_ROOT = 0x100         # specify tree root
-NLM_F_MATCH = 0x200        # return all matching
-NLM_F_ATOMIC = 0x400       # atomic GET
-NLM_F_DUMP = (NLM_F_ROOT|NLM_F_MATCH)
-
-# Modifiers to NEW request
-NLM_F_REPLACE = 0x100      # Override existing
-NLM_F_EXCL = 0x200         # Do not touch, if it exists
-NLM_F_CREATE = 0x400       # Create, if it does not exist
-NLM_F_APPEND = 0x800       # Add to end of list
-
-NLMSG_ALIGNTO = 4
-def NLMSG_ALIGN(len):
-    return (len + NLMSG_ALIGNTO - 1) & ~(NLMSG_ALIGNTO - 1)
-def NLMSG_HDRLEN():
-    return NLMSG_ALIGN(sizeof(Nlmsghdr))
-def NLMSG_LENGTH(len):
-    return len + NLMSG_ALIGN(NLMSG_HDRLEN())
-def NLMSG_SPACE(len):
-    return NLMSG_ALIGN(NLMSG_LENGTH(len))
-def NLMSG_DATA(nlh):
-    return addressof(nlh) + NLMSG_LENGTH(0)
-def NLMSG_NEXT(nlh, len):
-    cur = NLMSG_ALIGN(nlh.nlmsg_len)
-    nlh = Nlmsghdr.from_address(addressof(nlh) + cur)
-    return len - cur, nlh
-def NLMSG_OK(nlh, len):
-    return len >= sizeof(Nlmsghdr) and \
-        nlh.nlmsg_len >= sizeof(Nlmsghdr) and \
-        nlh.nlmsg_len <= len
-
-class Nlmsgerr(Structure):
-
-    _fields_ = [
-        ('error', c_int),
-        ('msg', Nlmsghdr),
-    ]
-
-class NetlinkError(Exception):
-
-    def __init__(self, message):
-        Exception.__init__(self, message)
-        #print(message)
-
-class Netlink(socket.socket):
-
-    def __init__(self, pid, proto):
-
-        self.pid = pid
-        self.recvbuf = bytearray(8 * 1024)
-        self.sendbuf = bytearray(8 * 1024)
-        self.seq = int(time())
-
-        try:
-
-            socket.socket.__init__(self, socket.AF_NETLINK, \
-                socket.SOCK_RAW, proto)
-            self.setblocking(0)
-
-            # Need to turn off ENOBUFS for netlink socket otherwise
-            # in a kernel overrun situation, the socket will return
-            # ENOBUFS on socket recv and be stuck for future recvs.
-
-            self.setsockopt(SOL_NETLINK, NETLINK_NO_ENOBUFS, 1)
-
-        except socket.error as (errno, string):
-            raise NetlinkError("open: socket err[%d]: %s" % \
-                (errno, string))
-
-    def bind(self, groups, cb):
-
-        self._nl_cb = cb
-
-        try:
-            socket.socket.bind(self, (self.pid, groups))
-
-        except socket.error as (errno, string):
-            raise NetlinkError("bind: socket err[%d]: %s" % \
-                (errno, string))
-
-    def sendall(self, string):
-        try:
-            socket.socket.sendall(self, string)
-        except socket.error as (errno, string):
-            raise NetlinkError("send: socket err[%d]: %s" % \
-                (errno, string))
-
-    def _process_nlh(self, recv, nlh):
-        while NLMSG_OK(nlh, recv):
-            yield recv, nlh
-            recv, nlh = NLMSG_NEXT(nlh, recv)
-
-    def process(self, tokens=[]):
-
-        found_done = False
-
-        try:
-            recv, src_addr = self.recvfrom_into(self.recvbuf)
-            if not recv:
-                # EOF
-                print "EOF"
-                return False
-
-        except socket.error as (errno, string):
-            if errno in [EINTR, EAGAIN]:
-                return False
-            raise NetlinkError("netlink: socket err[%d]: %s" % \
-                (errno, string))
-
-        nlh = Nlmsghdr.from_buffer(self.recvbuf)
-        for recv, nlh in self._process_nlh(recv, nlh):
-
-#            print "type %u, seq %u, pid %u" % \
-#                (nlh.nlmsg_type, nlh.nlmsg_seq, nlh.nlmsg_pid)
-
-            l = nlh.nlmsg_len - sizeof(Nlmsghdr)
-
-            if l < 0 or nlh.nlmsg_len > recv:
-                raise NetlinkError("netlink: malformed msg: len %d" % \
-                    nlh.nlmsg_len)
-
-            if tokens:
-                current = (nlh.nlmsg_pid, nlh.nlmsg_seq)
-                if current not in tokens:
-                    continue
-
-            if nlh.nlmsg_type == NLMSG_DONE:
-                found_done = True
-                break
-
-            if nlh.nlmsg_type == NLMSG_ERROR:
-                err = Nlmsgerr.from_address(NLMSG_DATA(nlh))
-                if err.error == 0:
-                    return False
-                raise NetlinkError("netlink: %s" % strerror(abs(err.error)))
-
-            if self._nl_cb:
-                self._nl_cb(nlh)
-
-        if found_done:
-            return False 
-
-        remnant = recv - NLMSG_ALIGN(nlh.nlmsg_len) > 0
-        if remnant:
-            raise NetlinkError("netlink: remnant of size %d" % \
-                remnant)
-
-        return True
-
-    def process_wait(self, tokens):
-        while self.process(tokens):
-            pass
-
-    def process_forever(self):
-        epoll = select.epoll()
-        epoll.register(self.fileno(), select.EPOLLIN)
-        while True:
-            events = epoll.poll()
-            for fileno, event in events:
-                if fileno == self.fileno():
-                    self.process()
-
-    def process_event(self, event):
-        return self.process()
diff --git a/ifupdown2/ifupdown/networkinterfaces.py b/ifupdown2/ifupdown/networkinterfaces.py
deleted file mode 100644 (file)
index f241e45..0000000
+++ /dev/null
@@ -1,437 +0,0 @@
-#!/usr/bin/python
-#
-# Copyright 2014 Cumulus Networks, Inc. All rights reserved.
-# Author: Roopa Prabhu, roopa@cumulusnetworks.com
-#
-# networkInterfaces --
-#    ifupdown network interfaces file parser
-#
-
-import collections
-import logging
-import glob
-import re
-import os
-import copy
-from utils import utils
-from iface import *
-from template import templateEngine
-
-whitespaces = '\n\t\r '
-
-class networkInterfaces():
-    """ debian ifupdown /etc/network/interfaces file parser """
-
-    hotplugs = {}
-    auto_ifaces = []
-    callbacks = {}
-    auto_all = False
-
-    _addrfams = {'inet' : ['static', 'manual', 'loopback', 'dhcp', 'dhcp6'],
-                 'inet6' : ['static', 'manual', 'loopback', 'dhcp', 'dhcp6']}
-
-    def __init__(self, interfacesfile='/etc/network/interfaces',
-                 interfacesfileiobuf=None, interfacesfileformat='native',
-                 template_engine=None, template_lookuppath=None):
-        """This member function initializes the networkinterfaces parser object.
-
-        Kwargs:
-            **interfacesfile** (str):  path to the interfaces file (default is /etc/network/interfaces)
-
-            **interfacesfileiobuf** (object): interfaces file io stream
-
-            **interfacesfileformat** (str): format of interfaces file (choices are 'native' and 'json'. 'native' being the default)
-
-            **template_engine** (str): template engine name
-
-            **template_lookuppath** (str): template lookup path
-
-        Raises:
-            AttributeError, KeyError """
-
-        self.logger = logging.getLogger('ifupdown.' +
-                    self.__class__.__name__)
-        self.callbacks = {'iface_found' : None,
-                          'validateifaceattr' : None,
-                          'validateifaceobj' : None}
-        self.allow_classes = {}
-        self.interfacesfile = interfacesfile
-        self.interfacesfileiobuf = interfacesfileiobuf
-        self.interfacesfileformat = interfacesfileformat
-        self._filestack = [self.interfacesfile]
-        self._template_engine = templateEngine(template_engine,
-                                    template_lookuppath)
-        self._currentfile_has_template = False
-        self._ws_split_regex = re.compile(r'[\s\t]\s*')
-
-    @property
-    def _currentfile(self):
-        try:
-            return self._filestack[-1]
-        except:
-            return self.interfacesfile
-
-    def _parse_error(self, filename, lineno, msg):
-        if lineno == -1 or self._currentfile_has_template:
-            self.logger.error('%s: %s' %(filename, msg))
-        else:
-            self.logger.error('%s: line%d: %s' %(filename, lineno, msg))
-
-    def _parse_warn(self, filename, lineno, msg):
-        if lineno == -1 or self._currentfile_has_template:
-            self.logger.warn('%s: %s' %(filename, msg))
-        else:
-            self.logger.warn('%s: line%d: %s' %(filename, lineno, msg))
-
-    def _validate_addr_family(self, ifaceobj, lineno=-1):
-        if ifaceobj.addr_family:
-            if not self._addrfams.get(ifaceobj.addr_family):
-                self._parse_error(self._currentfile, lineno,
-                    'iface %s: unsupported address family \'%s\''
-                    %(ifaceobj.name, ifaceobj.addr_family))
-                ifaceobj.addr_family = None
-                ifaceobj.addr_method = None
-                return
-            if ifaceobj.addr_method:
-                if (ifaceobj.addr_method not in
-                        self._addrfams.get(ifaceobj.addr_family)):
-                    self._parse_error(self._currentfile, lineno,
-                        'iface %s: unsupported address method \'%s\''
-                        %(ifaceobj.name, ifaceobj.addr_method))
-            else:
-                ifaceobj.addr_method = 'static'
-
-    def subscribe(self, callback_name, callback_func):
-        """This member function registers callback functions.
-
-        Args:
-            **callback_name** (str): callback function name (supported names: 'iface_found', 'validateifaceattr', 'validateifaceobj')
-
-            **callback_func** (function pointer): callback function pointer
-
-        Warns on error
-        """
-
-        if callback_name not in self.callbacks.keys():
-            print 'warning: invalid callback ' + callback_name
-            return -1
-
-        self.callbacks[callback_name] = callback_func
-
-    def ignore_line(self, line):
-        l = line.strip(whitespaces)
-        if not l or l[0] == '#':
-            return 1
-        return 0
-
-    def process_allow(self, lines, cur_idx, lineno):
-        allow_line = lines[cur_idx]
-
-        words = re.split(self._ws_split_regex, allow_line)
-        if len(words) <= 1:
-            raise Exception('invalid allow line \'%s\' at line %d'
-                            %(allow_line, lineno))
-
-        allow_class = words[0].split('-')[1]
-        ifacenames = words[1:]
-
-        if self.allow_classes.get(allow_class):
-            for i in ifacenames:
-                self.allow_classes[allow_class].append(i)
-        else:
-                self.allow_classes[allow_class] = ifacenames
-        return 0
-
-    def process_source(self, lines, cur_idx, lineno):
-        # Support regex
-        self.logger.debug('processing sourced line ..\'%s\'' %lines[cur_idx])
-        sourced_file = re.split(self._ws_split_regex, lines[cur_idx], 2)[1]
-        if sourced_file:
-            filenames = glob.glob(sourced_file)
-            if not filenames:
-                self._parse_warn(self._currentfile, lineno,
-                            'cannot find source file %s' %sourced_file)
-                return 0
-            for f in filenames:
-                self.read_file(f)
-        else:
-            self._parse_error(self._currentfile, lineno,
-                    'unable to read source line')
-        return 0
-
-    def process_auto(self, lines, cur_idx, lineno):
-        auto_ifaces = re.split(self._ws_split_regex, lines[cur_idx])[1:]
-        if not auto_ifaces:
-            self._parse_error(self._currentfile, lineno,
-                    'invalid auto line \'%s\''%lines[cur_idx])
-            return 0
-        for a in auto_ifaces:
-            if a == 'all':
-                self.auto_all = True
-                break
-            r = utils.parse_iface_range(a)
-            if r:
-                for i in range(r[1], r[2]):
-                   self.auto_ifaces.append('%s-%d' %(r[0], i))
-            self.auto_ifaces.append(a)
-        return 0
-
-    def _add_to_iface_config(self, ifacename, iface_config, attrname,
-                             attrval, lineno):
-        newattrname = attrname.replace("_", "-")
-        try:
-            if not self.callbacks.get('validateifaceattr')(newattrname,
-                                      attrval):
-                self._parse_error(self._currentfile, lineno,
-                        'iface %s: unsupported keyword (%s)'
-                        %(ifacename, attrname))
-                return
-        except:
-            pass
-        attrvallist = iface_config.get(newattrname, [])
-        if newattrname in ['scope', 'netmask', 'broadcast', 'preferred-lifetime']:
-            # For attributes that are related and that can have multiple
-            # entries, store them at the same index as their parent attribute.
-            # The example of such attributes is 'address' and its related
-            # attributes. since the related attributes can be optional, 
-            # we add null string '' in places where they are optional.
-            # XXX: this introduces awareness of attribute names in
-            # this class which is a violation.
-
-            # get the index corresponding to the 'address'
-            addrlist = iface_config.get('address')
-            if addrlist:
-                # find the index of last address element
-                for i in range(0, len(addrlist) - len(attrvallist) -1):
-                    attrvallist.append('')
-                attrvallist.append(attrval)
-                iface_config[newattrname] = attrvallist
-        elif not attrvallist:
-            iface_config[newattrname] = [attrval]
-        else:
-            iface_config[newattrname].append(attrval)
-
-    def parse_iface(self, lines, cur_idx, lineno, ifaceobj):
-        lines_consumed = 0
-        line_idx = cur_idx
-
-        iface_line = lines[cur_idx].strip(whitespaces)
-        iface_attrs = re.split(self._ws_split_regex, iface_line)
-        ifacename = iface_attrs[1]
-
-        # in cases where mako is unable to render the template
-        # or incorrectly renders it due to user template
-        # errors, we maybe left with interface names with
-        # mako variables in them. There is no easy way to
-        # recognize and warn about these. In the below check
-        # we try to warn the user of such cases by looking for
-        # variable patterns ('$') in interface names.
-        if '$' in ifacename:
-           self._parse_warn(self._currentfile, lineno,
-                    '%s: unexpected characters in interface name' %ifacename)
-
-        ifaceobj.raw_config.append(iface_line)
-        iface_config = collections.OrderedDict()
-        for line_idx in range(cur_idx + 1, len(lines)):
-            l = lines[line_idx].strip(whitespaces)
-            if self.ignore_line(l) == 1:
-                continue
-            attrs = re.split(self._ws_split_regex, l, 1)
-            if self._is_keyword(attrs[0]):
-                line_idx -= 1
-                break
-            # if not a keyword, every line must have at least a key and value
-            if len(attrs) < 2:
-                self._parse_error(self._currentfile, line_idx,
-                        'iface %s: invalid syntax \'%s\'' %(ifacename, l))
-                continue
-            ifaceobj.raw_config.append(l)
-            attrname = attrs[0]
-            # preprocess vars (XXX: only preprocesses $IFACE for now)
-            attrval = re.sub(r'\$IFACE', ifacename, attrs[1])
-            self._add_to_iface_config(ifacename, iface_config, attrname,
-                                      attrval, line_idx+1)
-        lines_consumed = line_idx - cur_idx
-
-        # Create iface object
-        if ifacename.find(':') != -1:
-            ifaceobj.name = ifacename.split(':')[0]
-        else:
-            ifaceobj.name = ifacename
-
-        ifaceobj.config = iface_config
-        ifaceobj.generate_env()
-
-        try:
-            ifaceobj.addr_family = iface_attrs[2]
-            ifaceobj.addr_method = iface_attrs[3]
-        except IndexError:
-            # ignore
-            pass
-        self._validate_addr_family(ifaceobj, lineno)
-
-        if self.auto_all or (ifaceobj.name in self.auto_ifaces):
-            ifaceobj.auto = True
-
-        classes = self.get_allow_classes_for_iface(ifaceobj.name)
-        if classes:
-            [ifaceobj.set_class(c) for c in classes]
-        
-        return lines_consumed       # Return next index
-
-    def process_iface(self, lines, cur_idx, lineno):
-        ifaceobj = iface()
-        lines_consumed = self.parse_iface(lines, cur_idx, lineno, ifaceobj)
-
-        range_val = utils.parse_iface_range(ifaceobj.name)
-        if range_val:
-           for v in range(range_val[1], range_val[2]):
-                ifaceobj_new = copy.deepcopy(ifaceobj)
-                ifaceobj_new.realname = '%s' %ifaceobj.name
-                ifaceobj_new.name = '%s%d' %(range_val[0], v)
-                ifaceobj_new.flags = iface.IFACERANGE_ENTRY
-                if v == range_val[1]:
-                    ifaceobj_new.flags |= iface.IFACERANGE_START
-                self.callbacks.get('iface_found')(ifaceobj_new)
-        else:
-            self.callbacks.get('iface_found')(ifaceobj)
-
-        return lines_consumed       # Return next index
-
-    def process_vlan(self, lines, cur_idx, lineno):
-        ifaceobj = iface()
-        lines_consumed = self.parse_iface(lines, cur_idx, lineno, ifaceobj)
-
-        range_val = utils.parse_iface_range(ifaceobj.name)
-        if range_val:
-           for v in range(range_val[1], range_val[2]):
-                ifaceobj_new = copy.deepcopy(ifaceobj)
-                ifaceobj_new.realname = '%s' %ifaceobj.name
-                ifaceobj_new.name = '%s%d' %(range_val[0], v)
-                ifaceobj_new.type = ifaceType.BRIDGE_VLAN
-                ifaceobj_new.flags = iface.IFACERANGE_ENTRY
-                if v == range_val[1]:
-                    ifaceobj_new.flags |= iface.IFACERANGE_START
-                self.callbacks.get('iface_found')(ifaceobj_new)
-        else:
-            ifaceobj.type = ifaceType.BRIDGE_VLAN
-            self.callbacks.get('iface_found')(ifaceobj)
-
-        return lines_consumed       # Return next index
-
-    network_elems = { 'source'      : process_source,
-                      'allow'      : process_allow,
-                      'auto'        : process_auto,
-                      'iface'       : process_iface,
-                      'vlan'       : process_vlan}
-
-    def _is_keyword(self, str):
-        # The additional split here is for allow- keyword
-        tmp_str = str.split('-')[0]
-        if tmp_str in self.network_elems.keys():
-            return 1
-        return 0
-
-    def _get_keyword_func(self, str):
-        tmp_str = str.split('-')[0]
-        return self.network_elems.get(tmp_str)
-
-    def get_allow_classes_for_iface(self, ifacename):
-        classes = []
-        for class_name, ifacenames in self.allow_classes.items():
-            if ifacename in ifacenames:
-                classes.append(class_name)
-        return classes
-
-    def process_interfaces(self, filedata):
-
-        # process line continuations
-        filedata = ' '.join(d.strip() for d in filedata.split('\\'))
-
-        line_idx = 0
-        lines_consumed = 0
-        raw_config = filedata.split('\n')
-        lines = [l.strip(whitespaces) for l in raw_config]
-        while (line_idx < len(lines)):
-            if self.ignore_line(lines[line_idx]):
-                line_idx += 1
-                continue
-            words = re.split(self._ws_split_regex, lines[line_idx])
-            if not words:
-                line_idx += 1
-                continue
-            # Check if first element is a supported keyword
-            if self._is_keyword(words[0]):
-                keyword_func = self._get_keyword_func(words[0])
-                lines_consumed = keyword_func(self, lines, line_idx, line_idx+1)
-                line_idx += lines_consumed
-            else:
-                self._parse_error(self._currentfile, line_idx + 1,
-                        'error processing line \'%s\'' %lines[line_idx])
-            line_idx += 1
-        return 0
-
-    def read_filedata(self, filedata):
-        self._currentfile_has_template = False
-        # run through template engine
-        try:
-            rendered_filedata = self._template_engine.render(filedata)
-            if rendered_filedata is filedata:
-                self._currentfile_has_template = False
-            else:
-                self._currentfile_has_template = True
-        except Exception, e:
-            self._parse_error(self._currentfile, -1,
-                    'failed to render template (%s). ' %str(e) +
-                    'Continue without template rendering ...')
-            rendered_filedata = None
-            pass
-        if rendered_filedata:
-            self.process_interfaces(rendered_filedata)
-        else:
-            self.process_interfaces(filedata)
-
-    def read_file(self, filename, fileiobuf=None):
-        if fileiobuf:
-            self.read_filedata(fileiobuf)
-            return
-        self._filestack.append(filename)
-        self.logger.info('processing interfaces file %s' %filename)
-        f = open(filename)
-        filedata = f.read()
-        f.close()
-        self.read_filedata(filedata)
-        self._filestack.pop()
-
-    def read_file_json(self, filename, fileiobuf=None):
-        if fileiobuf:
-            ifacedicts = json.loads(fileiobuf, encoding="utf-8")
-                              #object_hook=ifaceJsonDecoder.json_object_hook)
-        elif filename:
-            self.logger.info('processing interfaces file %s' %filename)
-            fp = open(filename)
-            ifacedicts = json.load(fp)
-                            #object_hook=ifaceJsonDecoder.json_object_hook)
-
-        # we need to handle both lists and non lists formats (e.g. {{}})
-        if not isinstance(ifacedicts,list):
-            ifacedicts = [ifacedicts]
-
-        for ifacedict in ifacedicts:
-            ifaceobj = ifaceJsonDecoder.json_to_ifaceobj(ifacedict)
-            if ifaceobj:
-                self._validate_addr_family(ifaceobj)
-                self.callbacks.get('validateifaceobj')(ifaceobj)
-                self.callbacks.get('iface_found')(ifaceobj)
-        
-    def load(self):
-        """ This member function loads the networkinterfaces file.
-
-        Assumes networkinterfaces parser object is initialized with the
-        parser arguments
-        """
-        if self.interfacesfileformat == 'json':
-            return self.read_file_json(self.interfacesfile,
-                                       self.interfacesfileiobuf)
-        return self.read_file(self.interfacesfile,
-                              self.interfacesfileiobuf)
diff --git a/ifupdown2/ifupdown/policymanager.py b/ifupdown2/ifupdown/policymanager.py
deleted file mode 100644 (file)
index 2f9cbac..0000000
+++ /dev/null
@@ -1,175 +0,0 @@
-#!/usr/bin/python
-#
-# Copyright 2015 Cumulus Networks, Inc. All rights reserved.
-#
-#
-'''
-The PolicyManager should be subclassed by addon modules
-to read a JSON policy config file that is later used to
-set defaults:
-
-Initialize: This module defines a list of config file location based
-          on module.  There are defined in the __init__():  All the
-          addon modules need to do is import the policymanager module.
-
-          import ifupdown.policymanager as policymanager
-
-
-Provides: an API to retrieve link attributes based on addon module name,
-          interface name, and attribute.
-
-        The ifupdown.policymanager module provides a global object policymanager_api
-        that can be called like so:
-
-        speed_default = policymanager.policymanager_api.get_default(
-            module_name='ethtool',
-            ifname=ifaceobj.name,
-            attr='link-speed'
-            )
-'''
-
-import json
-import logging
-import glob
-
-class policymanager():
-    def __init__(self):
-        # we should check for these files in order
-        # so that customers can override the /var/lib file settings
-        self.logger = logging.getLogger('ifupdown.' +
-                            self.__class__.__name__)
-
-        # we grab the json files from a known location and make sure that
-        # the defaults_policy is checked first
-        user_files = glob.glob('/etc/network/ifupdown2/policy.d/*.json')
-        # grab the default module files
-        default_files = glob.glob('/var/lib/ifupdownaddons/policy.d/*.json')
-        # keep an array of defaults indexed by module name
-        self.system_policy_array = {}
-        for filename in default_files:
-            system_array  = {}
-            try:
-                fd = open(filename,'r')
-                system_array = json.load(fd)
-                self.logger.debug('reading %s system policy defaults config' \
-                                  % filename)
-            except Exception, e:
-                self.logger.debug('could not read %s system policy defaults config' \
-                                  % filename)
-                self.logger.debug('    exception is %s' % str(e))
-            for module in system_array.keys():
-                if self.system_policy_array.has_key(module):
-                    self.logger.debug('warning: overwriting system module %s from file %s' \
-                                      % (module,filename))
-                self.system_policy_array[module] = system_array[module]
-
-        # take care of user defined policy defaults
-        self.user_policy_array = {}
-        for filename in user_files:
-            user_array  = {}
-            try:
-                fd = open(filename,'r')
-                user_array = json.load(fd)
-                self.logger.debug('reading %s policy user defaults config' \
-                                  % filename)
-            except Exception, e:
-                self.logger.debug('could not read %s user policy defaults config' \
-                                  % filename)
-                self.logger.debug('    exception is %s' % str(e))
-            # customer added module attributes
-            for module in user_array.keys():
-                if self.system_policy_array.has_key(module):
-                    # warn user that we are overriding the system module setting
-                    self.logger.debug('warning: overwriting system with user module %s from file %s' \
-                                      % (module,filename))
-                self.user_policy_array[module] = user_array[module]
-        return
-
-    def get_iface_default(self,module_name=None,ifname=None,attr=None):
-        '''
-        get_iface_default: Addon modules must use one of two types of access methods to
-        the default configs.   In this method, we expect the default to be
-        either in
-            [module]['iface_defaults'][ifname][attr] or
-            [module]['defaults'][attr]
-        We first check the user_policy_array and return that value. But if
-        the user did not specify an override, we use the system_policy_array.
-        '''
-        # make sure we have an index
-        if (not ifname or not attr or not module_name):
-            return None
-
-        val = None
-        # users can specify defaults to override the systemwide settings
-        # look for user specific interface attribute iface_defaults first
-        try:
-            # looks for user specified value
-            val = self.user_policy_array[module_name]['iface_defaults'][ifname][attr]
-            return val
-        except:
-            pass
-        try:
-            # failing that, there may be a user default for all intefaces
-            val = self.user_policy_array[module_name]['defaults'][attr]
-            return val
-        except:
-            pass
-        try:
-            # failing that, look for  system setting for the interface
-            val = self.system_policy_array[module_name]['iface_defaults'][ifname][attr]
-            return val
-        except:
-            pass
-        try:
-            # failing that, look for  system setting for all interfaces
-            val = self.system_policy_array[module_name]['defaults'][attr]
-            return val
-        except:
-            pass
-
-        # could not find any system or user default so return Non
-        return val
-
-    def get_attr_default(self,module_name=None,attr=None):
-        '''
-        get_attr_default: Addon modules must use one of two types of access methods to
-        the default configs.   In this method, we expect the default to be in
-
-        [module][attr] 
-
-        We first check the user_policy_array and return that value. But if
-        the user did not specify an override, we use the system_policy_array.
-        '''
-        if (not attr or not module_name):
-            return None
-        # users can specify defaults to override the systemwide settings
-        # look for user specific interface attribute iface_defaults first
-        val = None
-        if self.user_policy_array.get(module_name):
-            val = self.user_policy_array[module_name].get(attr)
-
-        if not val:
-            if self.system_policy_array.get(module_name):
-                val = self.system_policy_array[module_name].get(attr)
-
-        return val
-
-    def get_module_default(self,module_name=None):
-        '''
-        get_module_default: Addon modules can also access the entire config
-        This method returns indexed by "system" and "user": these are the
-        system-wide and user-defined policy arrays for a specific module.
-        '''
-        if not module_name:
-            return None
-        if self.system_policy_array.get(module_name) and \
-           self.user_policy_array.get(module_name):
-            mod_array = {"system":self.system_policy_array[module_name],
-                         "user":self.user_policy_array[module_name]}
-        else:
-            # the module must not have these defined, return None
-            mod_array = None
-
-        return mod_array
-
-policymanager_api = policymanager()
diff --git a/ifupdown2/ifupdown/rtnetlink.py b/ifupdown2/ifupdown/rtnetlink.py
deleted file mode 100644 (file)
index 9b13ad5..0000000
+++ /dev/null
@@ -1,860 +0,0 @@
-#!/usr/bin/env python
-#
-# Copyright 2014 Cumulus Networks, Inc. All rights reserved.
-#
-# Author: Scott Feldman, sfeldma@cumulusnetworks.com
-# Author: Roopa Prabhu, roopa@cumulusnetworks.com
-#
-#
-from socket import NETLINK_ROUTE, AF_INET, AF_INET6
-from string import printable
-from ipaddr import *
-from ctypes import *
-from netlink import *
-import logging
-
-logger = logging.getLogger(__name__)
-
-#
-# from /usr/include/linux/rtnetlink.h
-#
-
-RTMGRP_LINK = 0x1
-RTMGRP_IPV4_IFADDR = 0x10
-RTMGRP_IPV4_ROUTE = 0x40
-RTMGRP_IPV6_IFADDR = 0x100
-RTMGRP_IPV6_ROUTE = 0x400
-
-RTM_NEWLINK = 16
-RTM_DELLINK = 17
-RTM_GETLINK = 18
-RTM_SETLINK = 19
-RTM_NEWADDR = 20
-RTM_DELADDR = 21
-RTM_GETADDR = 22
-RTM_NEWROUTE = 24
-RTM_DELROUTE = 25
-RTM_GETROUTE = 26
-
-# Definitions used in routing table administration.
-
-class Nlmsg(Structure):
-
-    def _stringify(self):
-        return string_at(addressof(self), sizeof(self))
-
-    def __eq__(self, other):
-        return self._stringify() == other._stringify() and \
-            self.__dict__ == other.__dict__
-
-    def to_rta(self):
-        return Rtattr.from_address(addressof(self) + NLMSG_ALIGN(sizeof(self)))
-
-    def pack_extra(self, extra, addr):
-        memmove(addr, addressof(extra), sizeof(extra))
-        return NLMSG_ALIGN(sizeof(extra))
-
-    def pack_rtas(self, rtas, addr):
-        total_len = 0
-        for rta_type, value in rtas.iteritems():
-            rta = Rtattr.from_address(addr)
-            rta.rta_type = rta_type
-            pack_fn = self.rta_fn(rta_type)
-            rta_len = NLMSG_ALIGN(pack_fn(rta, value))
-            total_len += rta_len
-            addr += rta_len
-        return total_len
-
-    def pack_rtas_new(self, rtas, addr, policy):
-        total_len = 0
-                
-        for rta_type, value in rtas.iteritems():
-            if type(value) == dict:
-               rta = Rtattr.from_address(addr)
-               rta.rta_type = rta_type
-                rta.rta_len = RTA_LENGTH(0)
-                rta_len = NLMSG_ALIGN(rta.rta_len)
-                total_len += rta_len
-                addr += rta_len
-               pack_fn = policy.get(rta_type)
-                rta_len = NLMSG_ALIGN(pack_fn(addr, value))
-
-                rta.rta_len += rta_len
-            else:
-                rta = Rtattr.from_address(addr)
-                rta.rta_type = rta_type
-                pack_fn = policy.get(rta_type)
-                rta_len = NLMSG_ALIGN(pack_fn(rta, value))
-            total_len += rta_len
-            addr += rta_len
-        return total_len
-
-    def rta_linkinfo(self, addr, rtas):
-        total_len = 0
-
-        # Check interface kind 
-        kind = rtas.get(IFLA_INFO_KIND)
-        if kind == 'vlan':
-            data_policy = self.rta_linkinfo_data_vlan_policy()
-        else:
-            data_policy = self.rta_linkinfo_data_macvlan_policy()
-
-        # Pack info kind
-        rta = Rtattr.from_address(addr)
-        rta.rta_type = IFLA_INFO_KIND
-        rta_len = NLMSG_ALIGN(self.rta_string(rta, kind))
-        total_len += rta_len
-        addr += rta_len
-
-        # nest start link info data
-        rta = Rtattr.from_address(addr)
-        rta.rta_type = IFLA_INFO_DATA
-        rta.rta_len = RTA_LENGTH(0)
-        rta_len = NLMSG_ALIGN(rta.rta_len)
-        total_len += rta_len
-        addr += rta_len
-        rta_len = self.pack_rtas_new(rtas.get(IFLA_INFO_DATA), addr,
-                                     data_policy)
-        rta.rta_len += rta_len
-
-        total_len += rta_len
-        addr += rta_len
-
-        return total_len
-
-    def rta_bridge_vlan_info(self, rta, value):
-        if value:
-           data = RTA_DATA(rta)
-           memmove(data, addressof(value), sizeof(value))
-           rta.rta_len = RTA_LENGTH(sizeof(value))
-           return rta.rta_len
-
-    def rta_af_spec(self, addr, rtas):
-        total_len = 0
-
-        # XXX: Check family (Assumes bridge family for now)
-        rta_len = self.pack_rtas_new(rtas, addr,
-                                     self.rta_bridge_af_spec_policy())
-        total_len += rta_len
-        return total_len
-
-    def unpack_rtas(self, which_ones=[]):
-        len = self.nlh.nlmsg_len - NLMSG_LENGTH(sizeof(self))
-        rta = self.to_rta()
-        rtas = {}
-        while RTA_OK(rta, len):
-            rta_type = rta.rta_type
-            if not which_ones or rta_type in which_ones:
-                unpack_fn = self.rta_fn(rta_type)
-                rtas[rta_type] = unpack_fn(rta)
-            len, rta = RTA_NEXT(rta, len)
-        return rtas
-
-    def dump_rtas(self):
-        rtas = self.unpack_rtas()
-        for type, value in rtas.iteritems():
-            print "rta", type, ":", value
-
-    class _IPv6Addr(BigEndianStructure):
-        _fields_ = [
-            ('upper', c_uint64),
-            ('lower', c_uint64),
-        ]
-
-    class _IPv4Addr(BigEndianStructure):
-        _fields_ = [
-            ('addr', c_uint32),
-        ]
-
-    def rta_uint8(self, rta, value=None):
-        data = RTA_DATA(rta)
-        if value:
-            c_uint8.from_address(data).value = value
-            rta.rta_len = RTA_LENGTH(sizeof(c_uint8))
-            return rta.rta_len
-       else:
-            return c_uint8.from_address(data).value
-
-    def rta_uint16(self, rta, value=None):
-        data = RTA_DATA(rta)
-        if value:
-            c_uint16.from_address(data).value = value
-            rta.rta_len = RTA_LENGTH(sizeof(c_uint16))
-            return rta.rta_len
-       else:
-            return c_uint16.from_address(data).value
-
-    def rta_uint32(self, rta, value=None):
-        data = RTA_DATA(rta)
-        if value:
-            c_uint32.from_address(data).value = value
-            rta.rta_len = RTA_LENGTH(sizeof(c_uint32))
-            return rta.rta_len
-        else:
-            return c_uint32.from_address(data).value
-
-    def rta_string(self, rta, value=None):
-        data = RTA_DATA(rta)
-        if value:
-            s = create_string_buffer(value)
-            memmove(data, addressof(s), len(value))
-            rta.rta_len = RTA_LENGTH(len(value))
-            return rta.rta_len
-        else:
-            return c_char_p(data).value
-
-    def rta_addr(self, rta, value=None):
-        data = RTA_DATA(rta)
-        if value:
-            if isinstance(value, IPv4Address):
-                self._IPv4Addr.from_address(data).addr = value._ip
-                rta.rta_len = RTA_LENGTH(sizeof(self._IPv4Addr))
-            elif isinstance(value, IPv6Address):
-                addr = self._IPv6Addr.from_address(data)
-                addr.upper = value._ip >> 64
-                addr.lower = value._ip & 0xffffffffffffffff
-                rta.rta_len = RTA_LENGTH(sizeof(self._IPv6Addr))
-            else:
-                assert(False)
-            return rta.rta_len
-        else:
-            if RTA_PAYLOAD(rta) == 4:
-                addr = c_uint32.__ctype_be__.from_address(data).value
-                addr = IPv4Address(addr)
-            else:
-                addr = self._IPv6Addr.from_address(data)
-                addr = IPv6Address((addr.upper << 64) + addr.lower)
-            return addr
-
-    def rta_uint8_array(self, rta, value=None):
-        data = RTA_DATA(rta)
-        if value:
-            s = (c_uint8 * len(value)).from_buffer_copy(value)
-            memmove(data, addressof(s), len(value))
-            rta.rta_len = RTA_LENGTH(len(value))
-            return rta.rta_len
-        else:
-            array = (c_uint8 * RTA_PAYLOAD(rta))()
-            memmove(array, data, RTA_PAYLOAD(rta))
-            return array
-
-    def rta_uint32_array(self, rta, value=None):
-        if value:
-            assert(False)
-        else:
-            data = RTA_DATA(rta)
-            size = RTA_PAYLOAD(rta) / sizeof(c_uint32)
-            array = (c_uint32 * size)()
-            memmove(array, data, RTA_PAYLOAD(rta))
-            return array
-
-    def rta_multipath(self, rta, value=None):
-        # XXX implement this
-        return None
-
-    def rta_wtf(self, rta, value=None):
-        return None
-
-    def rta_none(self, rta, value=None):
-        return None
-
-    def rta_fn(self, rta_type):
-        return None
-
-
-# rtm_type
-
-RTN_UNSPEC = 0
-RTN_UNICAST = 1            # Gateway or direct route
-RTN_LOCAL = 2              # Accept locally
-RTN_BROADCAST = 3          # Accept locally as broadcast,
-                           # send as broadcast
-RTN_ANYCAST = 4            # Accept locally as broadcast,
-                           # but send as unicast
-RTN_MULTICAST = 5          # Multicast route
-RTN_BLACKHOLE = 6          # Drop
-RTN_UNREACHABLE = 7        # Destination is unreachable
-RTN_PROHIBIT = 8           # Administratively prohibited
-RTN_THROW = 9              # Not in this table
-RTN_NAT = 10               # Translate this address
-RTN_XRESOLVE = 11          # Use external resolver
-RTN_MAX = 11
-
-# rtm_protocol
-
-RTPROT_UNSPEC = 0
-RTPROT_REDIRECT = 1     # Route installed by ICMP redirects;
-                        # not used by current IPv4
-RTPROT_KERNEL = 2       # Route installed by kernel
-RTPROT_BOOT = 3         # Route installed during boot
-RTPROT_STATIC = 4       # Route installed by administrator
-
-# Values of protocol >= RTPROT_STATIC are not interpreted by kernel;
-# they are just passed from user and back as is.
-# It will be used by hypothetical multiple routing daemons.
-# Note that protocol values should be standardized in order to
-# avoid conflicts.
-
-RTPROT_GATED = 8       # Apparently, GateD
-RTPROT_RA = 9          # RDISC/ND router advertisements
-RTPROT_MRT = 10        # Merit MRT
-RTPROT_ZEBRA = 11      # Zebra
-RTPROT_BIRD = 12       # BIRD
-RTPROT_DNROUTED = 13   # DECnet routing daemon
-RTPROT_XORP = 14       # XORP
-RTPROT_NTK = 15        # Netsukuku
-RTPROT_DHCP = 16       # DHCP client
-
-# rtm_scope
-
-# Really it is not scope, but sort of distance to the destination.
-# NOWHERE are reserved for not existing destinations, HOST is our
-# local addresses, LINK are destinations, located on directly attached
-# link and UNIVERSE is everywhere in the Universe.
-
-# Intermediate values are also possible f.e. interior routes
-# could be assigned a value between UNIVERSE and LINK.
-
-RT_SCOPE_UNIVERSE = 0
-# User defined values
-RT_SCOPE_SITE = 200
-RT_SCOPE_LINK = 253
-RT_SCOPE_HOST = 254
-RT_SCOPE_NOWHERE=255
-
-# rtm_flags
-
-RTM_F_NOTIFY = 0x100   # Notify user of route change
-RTM_F_CLONED = 0x200   # This route is cloned
-RTM_F_EQUALIZE = 0x400 # Multipath equalizer: NI
-RTM_F_PREFIX = 0x800   # Prefix addresses
-
-# Reserved table identifiers
-
-RT_TABLE_UNSPEC = 0
-# User defined values
-RT_TABLE_COMPAT = 252
-RT_TABLE_DEFAULT = 253
-RT_TABLE_MAIN = 254
-RT_TABLE_LOCAL = 255
-RT_TABLE_MAX = 0xFFFFFFFF
-
-# Generic structure for encapsulation of optional route information.
-# It is reminiscent of sockaddr, but with sa_family replaced
-# with attribute type.
-
-class Rtattr(Structure):
-
-    _fields_ = [
-        ('rta_len', c_uint16),
-        ('rta_type', c_uint16),
-    ]
-
-# Routing message attributes
-
-RTA_UNSPEC = 0
-RTA_DST = 1
-RTA_SRC = 2
-RTA_IIF = 3
-RTA_OIF = 4
-RTA_GATEWAY = 5
-RTA_PRIORITY = 6
-RTA_PREFSRC = 7
-RTA_METRICS = 8
-RTA_MULTIPATH = 9
-RTA_PROTOINFO = 10        # no longer used
-RTA_FLOW = 11
-RTA_CACHEINFO = 12
-RTA_SESSION = 13          # no longer used
-RTA_MP_ALGO = 14          # no longer used 
-RTA_TABLE = 15
-RTA_MAX = 15
-
-# Macros to handle rtattributes
-
-RTA_ALIGNTO = 4
-def RTA_ALIGN(len):
-    return (len + RTA_ALIGNTO - 1) & ~(RTA_ALIGNTO - 1)
-def RTA_OK(rta, len):
-    return len >= sizeof(Rtattr) and \
-        rta.rta_len >= sizeof(Rtattr) and \
-        rta.rta_len <= len
-def RTA_NEXT(rta, len):
-    cur = RTA_ALIGN(rta.rta_len)
-    rta = Rtattr.from_address(addressof(rta) + cur)
-    return len - cur, rta
-def RTA_LENGTH(len):
-    return len + RTA_ALIGN(sizeof(Rtattr))
-def RTA_SPACE(len):
-    return RTA_ALIGN(RTA_LENGTH(len))
-def RTA_DATA(rta):
-    return addressof(rta) + RTA_LENGTH(0)
-def RTA_PAYLOAD(rta):
-    return rta.rta_len - RTA_LENGTH(0)
-
-RTNH_F_DEAD = 1         # Nexthop is dead (used by multipath)
-RTNH_F_PERVASIVE = 2    # Do recursive gateway lookup
-RTNH_F_ONLINK = 4       # Gateway is forced on link
-
-# Reserved table identifiers
-
-RT_TABLE_UNSPEC = 0
-# User defined values
-RT_TABLE_COMPAT = 252
-RT_TABLE_DEFAULT = 253
-RT_TABLE_MAIN = 254
-RT_TABLE_LOCAL = 255
-RT_TABLE_MAX = 0xFFFFFFFF
-
-class Rtmsg(Nlmsg):
-
-    _fields_ = [
-        ('rtm_family', c_uint8),
-        ('rtm_dst_len', c_uint8),
-        ('rtm_src_len', c_uint8),
-        ('rtm_tos', c_uint8),
-        ('rtm_table', c_uint8),
-        ('rtm_protocol', c_uint8),
-        ('rtm_scope', c_uint8),
-        ('rtm_type', c_uint8),
-        ('rtm_flags', c_uint32),
-    ]
-
-    _table_str = {
-        RT_TABLE_UNSPEC: "unspecified",
-        RT_TABLE_COMPAT: "compat",
-        RT_TABLE_DEFAULT: "default",
-        RT_TABLE_MAIN: "main",
-        RT_TABLE_LOCAL: "local",
-    }
-
-    _proto_str = {
-        RTPROT_UNSPEC: "none",
-        RTPROT_REDIRECT: "redirect",
-        RTPROT_KERNEL: "kernel",
-        RTPROT_BOOT: "boot",
-        RTPROT_STATIC: "static",
-        RTPROT_GATED: "gated",
-        RTPROT_RA: "ra",
-        RTPROT_MRT: "mrtmrt",
-        RTPROT_ZEBRA: "zebra",
-        RTPROT_BIRD: "bird",
-        RTPROT_DNROUTED: "dnrouted",
-        RTPROT_XORP: "xorp",
-        RTPROT_NTK: "ntk",
-        RTPROT_DHCP: "dhcp",
-    }
-
-    _scope_str = {
-        RT_SCOPE_UNIVERSE: "universe",
-        RT_SCOPE_SITE: "site",
-        RT_SCOPE_LINK: "link",
-        RT_SCOPE_HOST: "host",
-        RT_SCOPE_NOWHERE: "nowhere",
-    }
-
-    _type_str = {
-        RTN_UNSPEC: "unspecified",
-        RTN_UNICAST: "unicast",
-        RTN_LOCAL: "local",
-        RTN_BROADCAST: "broadcast",
-        RTN_ANYCAST: "anycast",
-        RTN_MULTICAST: "multicast",
-        RTN_BLACKHOLE: "blackhole",
-        RTN_UNREACHABLE: "unreachable",
-        RTN_PROHIBIT: "prohibit",
-        RTN_THROW: "throw",
-        RTN_NAT: "nat",
-        RTN_XRESOLVE: "xresolve",
-    }
-
-    def dump(self):
-        print 'rtm_family', self.rtm_family
-        print 'rtm_dst_len', self.rtm_dst_len
-        print 'rtm_src_len', self.rtm_src_len
-        print 'rtm_tos', self.rtm_tos
-        print 'rtm_table', self._table_str.get(self.rtm_table, self.rtm_table)
-        print 'rtm_protocol', self._proto_str.get(self.rtm_protocol)
-        print 'rtm_scope', self._scope_str.get(self.rtm_scope)
-        print 'rtm_type', self._type_str.get(self.rtm_type)
-        print 'rtm_flags 0x%08x' % self.rtm_flags
-
-    def rta_fn(self, rta_type):
-        fns = {
-            RTA_DST: self.rta_addr,
-            RTA_SRC: self.rta_addr,
-            RTA_IIF: self.rta_uint32,
-            RTA_OIF: self.rta_uint32,
-            RTA_GATEWAY: self.rta_addr,
-            RTA_PRIORITY: self.rta_uint32,
-            RTA_PREFSRC: self.rta_addr,
-            RTA_METRICS: self.rta_uint32_array,
-            RTA_MULTIPATH: self.rta_multipath,
-            RTA_PROTOINFO: self.rta_none,
-            RTA_FLOW: self.rta_uint32,
-            RTA_CACHEINFO: self.rta_none,
-            RTA_SESSION: self.rta_none,
-            RTA_MP_ALGO: self.rta_none,
-            RTA_TABLE: self.rta_uint32,
-        }
-
-        return fns.get(rta_type)
-
-class Rtgenmsg(Nlmsg):
-
-    _fields_ = [
-        ('rtgen_family', c_uint8),
-    ]
-
-    def dump(self):
-        print 'rtgen_family', self.rtgen_family
-
-# New extended info filters for IFLA_EXT_MASK
-RTEXT_FILTER_VF = (1 << 0)
-
-# passes link level specific information, not dependent
-# on network protocol.
-
-IFLA_UNSPEC = 0
-IFLA_ADDRESS = 1
-IFLA_BROADCAST = 2
-IFLA_IFNAME = 3
-IFLA_MTU = 4
-IFLA_LINK = 5
-IFLA_QDISC = 6
-IFLA_STATS = 7
-IFLA_COST = 8
-IFLA_PRIORITY = 9
-IFLA_MASTER = 10
-IFLA_WIRELESS = 11          # Wireless Extension event - see wireless.h
-IFLA_PROTINFO = 12          # Protocol specific information for a link
-IFLA_TXQLEN = 13
-IFLA_MAP = 14
-IFLA_WEIGHT = 15
-IFLA_OPERSTATE = 16
-IFLA_LINKMODE = 17
-IFLA_LINKINFO = 18
-IFLA_NET_NS_PID = 19
-IFLA_IFALIAS = 20
-IFLA_NUM_VF = 21            # Number of VFs if device is SR-IOV PF
-IFLA_VFINFO_LIST = 22
-IFLA_STATS64 = 23
-IFLA_VF_PORTS = 24
-IFLA_PORT_SELF = 25
-IFLA_AF_SPEC = 26
-IFLA_GROUP = 27             # Group the device belongs to
-IFLA_NET_NS_FD = 28
-IFLA_EXT_MASK = 29          # Extended info mask, VFs, etc
-IFLA_MAX = 29
-
-
-# IFLA_LINKINFO attributes
-IFLA_INFO_UNSPEC = 0
-IFLA_INFO_KIND = 1
-IFLA_INFO_DATA = 2
-IFLA_INFO_XSTATS = 3
-IFLA_INFO_MAX = 4
-
-# IFLA_LINKINFO_DATA attributes for vlan
-IFLA_VLAN_UNSPEC = 0
-IFLA_VLAN_ID = 1
-
-# IFLA_LINKINFO_DATA attributes for macvlan
-IFLA_MACVLAN_UNSPEC = 0
-IFLA_MACVLAN_MODE = 1
-
-# macvlan modes
-MACVLAN_MODE_PRIVATE = 1
-MACVLAN_MODE_VEPA = 2
-MACVLAN_MODE_BRIDGE = 3
-MACVLAN_MODE_PASSTHRU = 4
-
-# BRIDGE IFLA_AF_SPEC attributes
-IFLA_BRIDGE_FLAGS = 0
-IFLA_BRIDGE_MODE = 1
-IFLA_BRIDGE_VLAN_INFO = 2
-
-# BRIDGE_VLAN_INFO flags
-BRIDGE_VLAN_INFO_MASTER = 1
-BRIDGE_VLAN_INFO_PVID = 2
-BRIDGE_VLAN_INFO_UNTAGGED = 4
-
-# Bridge flags
-BRIDGE_FLAGS_MASTER = 1
-BRIDGE_FLAGS_SELF = 2
-
-class BridgeVlanInfo(Structure):
-    _fields_ = [
-        ('flags', c_uint16),
-        ('vid', c_uint16),
-        ('vid_end', c_uint16),
-    ]
-
-class Ifinfomsg(Nlmsg):
-
-    _fields_ = [
-        ('ifi_family', c_uint8),
-        ('__ifi_pad', c_uint8),
-        ('ifi_type', c_uint16),      # ARPHRD_*
-        ('ifi_index', c_int32),      # Link index
-        ('ifi_flags', c_uint32),     # IFF_* flags
-        ('ifi_change', c_uint32),    # IFF_* change mask
-    ]
-
-    def dump(self):
-        print 'ifi_family', self.ifi_family
-        print 'ifi_type', self.ifi_type
-        print 'ifi_index', self.ifi_index
-        print 'ifi_flags 0x%08x' % self.ifi_flags
-        print 'ifi_change 0x%08x' % self.ifi_change
-
-    def rta_linkinfo_data_vlan_policy(self):
-        fns = {
-            IFLA_VLAN_ID : self.rta_uint16,
-        }
-        return fns
-
-    def rta_linkinfo_data_macvlan_policy(self):
-        fns = {
-            IFLA_MACVLAN_MODE : self.rta_uint32,
-        }
-        return fns
-
-    def rta_linkinfo_policy(self):
-        fns = {
-            IFLA_INFO_KIND : self.rta_string,
-            IFLA_INFO_DATA : self.rta_linkinfo_data,
-        }
-        return fns
-
-    def rta_bridge_af_spec_policy(self):
-        # Assume bridge family for now
-        fns = {
-            IFLA_BRIDGE_FLAGS : self.rta_uint16,
-            IFLA_BRIDGE_VLAN_INFO : self.rta_bridge_vlan_info,
-        }
-        return fns
-
-    def rta_policy(self):
-        fns = {
-            IFLA_UNSPEC: self.rta_wtf,
-            IFLA_ADDRESS: self.rta_uint8_array,
-            IFLA_BROADCAST: self.rta_uint8_array,
-            IFLA_IFNAME: self.rta_string,
-            IFLA_MTU: self.rta_uint32,
-            IFLA_LINK: self.rta_uint32,
-            IFLA_QDISC: self.rta_string,
-            IFLA_STATS: self.rta_none,
-            IFLA_COST: self.rta_none,
-            IFLA_PRIORITY: self.rta_none,
-            IFLA_MASTER: self.rta_uint32,
-            IFLA_WIRELESS: self.rta_none,
-            IFLA_PROTINFO: self.rta_none,
-            IFLA_TXQLEN: self.rta_uint32,
-            IFLA_MAP: self.rta_none,
-            IFLA_WEIGHT: self.rta_uint32,
-            IFLA_OPERSTATE: self.rta_uint8,
-            IFLA_LINKMODE: self.rta_uint8,
-            IFLA_LINKINFO: self.rta_linkinfo,
-            IFLA_NET_NS_PID: self.rta_uint32,
-            IFLA_IFALIAS: self.rta_string,
-            IFLA_NUM_VF: self.rta_uint32,
-            IFLA_VFINFO_LIST: self.rta_none,
-            IFLA_STATS64: self.rta_none,
-            IFLA_VF_PORTS: self.rta_none,
-            IFLA_PORT_SELF: self.rta_none,
-            IFLA_AF_SPEC: self.rta_af_spec,
-            IFLA_GROUP: self.rta_none,
-            IFLA_NET_NS_FD: self.rta_none,
-            IFLA_EXT_MASK: self.rta_none,
-        }
-        return fns;
-
-    def rta_fn(self, rta_type):
-        fns = {
-            IFLA_UNSPEC: self.rta_wtf,
-            IFLA_ADDRESS: self.rta_uint8_array,
-            IFLA_BROADCAST: self.rta_uint8_array,
-            IFLA_IFNAME: self.rta_string,
-            IFLA_MTU: self.rta_uint32,
-            IFLA_LINK: self.rta_uint32,
-            IFLA_QDISC: self.rta_string,
-            IFLA_STATS: self.rta_none,
-            IFLA_COST: self.rta_none,
-            IFLA_PRIORITY: self.rta_none,
-            IFLA_MASTER: self.rta_uint32,
-            IFLA_WIRELESS: self.rta_none,
-            IFLA_PROTINFO: self.rta_none,
-            IFLA_TXQLEN: self.rta_uint32,
-            IFLA_MAP: self.rta_none,
-            IFLA_WEIGHT: self.rta_uint32,
-            IFLA_OPERSTATE: self.rta_uint8,
-            IFLA_LINKMODE: self.rta_uint8,
-            IFLA_LINKINFO: self.rta_linkinfo,
-            IFLA_NET_NS_PID: self.rta_uint32,
-            IFLA_IFALIAS: self.rta_string,
-            IFLA_NUM_VF: self.rta_uint32,
-            IFLA_VFINFO_LIST: self.rta_none,
-            IFLA_STATS64: self.rta_none,
-            IFLA_VF_PORTS: self.rta_none,
-            IFLA_PORT_SELF: self.rta_none,
-            IFLA_AF_SPEC: self.rta_af_spec,
-            IFLA_GROUP: self.rta_none,
-            IFLA_NET_NS_FD: self.rta_none,
-            IFLA_EXT_MASK: self.rta_none,
-        }
-        return fns.get(rta_type)
-
-# passes address specific information
-
-# Important comment:
-# IFA_ADDRESS is prefix address, rather than local interface address.
-# It makes no difference for normally configured broadcast interfaces,
-# but for point-to-point IFA_ADDRESS is DESTINATION address,
-# local address is supplied in IFA_LOCAL attribute.
-
-IFA_UNSPEC = 0
-IFA_ADDRESS = 1
-IFA_LOCAL = 2
-IFA_LABEL = 3
-IFA_BROADCAST = 4
-IFA_ANYCAST = 5
-IFA_CACHEINFO = 6
-IFA_MULTICAST = 7
-IFA_MAX = 7
-
-class Ifaddrmsg(Nlmsg):
-
-    _fields_ = [
-        ('ifa_family', c_uint8),
-        ('ifa_prefixlen', c_uint8), # The prefix length
-        ('ifa_flags', c_uint8),     # Flags
-        ('ifa_scope', c_uint8),     # Address scope
-        ('ifa_index', c_uint32),    # Link index
-    ]
-
-    _family_str = {
-        AF_INET: "inet",
-        AF_INET6: "inet6",
-    }
-
-    def dump(self):
-        print 'ifa_family', self.ifa_family
-        print 'ifa_prefixlen', self.ifa_prefixlen
-        print 'ifa_flags 0x%02x' % self.ifa_flags
-        print 'ifa_scope', self.ifa_scope
-        print 'ifa_index', self.ifa_index
-
-    def rta_fn(self, rta_type):
-        fns = {
-            IFA_ADDRESS: self.rta_addr,
-            IFA_LOCAL: self.rta_addr,
-            IFA_LABEL: self.rta_string,
-            IFA_BROADCAST: self.rta_addr,
-            IFA_ANYCAST: self.rta_addr,
-            IFA_CACHEINFO: self.rta_none,
-            IFA_MULTICAST: self.rta_addr,
-        }
-        return fns.get(rta_type)
-
-class RtNetlinkError(Exception):
-
-    def __init__(self, message):
-        Exception.__init__(self, message)
-        logger.error(message)
-
-class RtNetlink(Netlink):
-
-    def __init__(self, pid):
-        Netlink.__init__(self, pid, NETLINK_ROUTE)
-
-    _rt_nlmsg_type_str = {
-        RTM_NEWROUTE: "RTM_NEWROUTE",
-        RTM_DELROUTE: "RTM_DELROUTE",
-        RTM_NEWLINK: "RTM_NEWLINK",
-        RTM_SETLINK: "RTM_SETLINK",
-        RTM_DELLINK: "RTM_DELLINK",
-        RTM_GETLINK: "RTM_GETLINK",
-        RTM_NEWADDR: "RTM_NEWADDR",
-        RTM_DELADDR: "RTM_DELADDR",
-    }
-
-    def _hexdump(self, buf):
-        while buf:
-            chunk = buf[:16]
-            buf = buf[16:]
-            nums = ["%02x" % c for c in chunk]
-            txt = [chr(c) if chr(c) in printable[:-5] else '.' for c in chunk]
-            print " ".join(nums).ljust(48), "".join(txt)
-
-    def dump(self, nlh):
-        nlmsg = self.nlmsg(nlh)
-        print
-        self._hexdump(self.sendbuf[:nlh.nlmsg_len])
-        print
-        nlh.dump()
-        print
-        nlmsg.dump()
-        print
-        nlmsg.dump_rtas()
-
-    def nlmsg(self, nlh):
-        nlmsg_struct = {
-            RTM_NEWROUTE: Rtmsg,
-            RTM_DELROUTE: Rtmsg,
-            RTM_GETROUTE: Rtmsg,
-            RTM_NEWLINK: Ifinfomsg,
-            RTM_SETLINK: Ifinfomsg,
-            RTM_DELLINK: Ifinfomsg,
-            RTM_GETLINK: Rtgenmsg,
-            RTM_NEWADDR: Ifaddrmsg,
-            RTM_DELADDR: Ifaddrmsg,
-            RTM_GETADDR: Rtgenmsg,
-        }
-        nldata = NLMSG_DATA(nlh)
-        nlmsg = nlmsg_struct[nlh.nlmsg_type].from_address(nldata)
-        nlmsg.nlh = nlh
-        return nlmsg
-
-    def _nl_cb(self, nlh):
-#        print "nl cb", self._rt_nlmsg_type_str[nlh.nlmsg_type]
-
-        if nlh.nlmsg_type in self._cbs:
-
-            nlmsg = self.nlmsg(nlh)
-
-            # validate nl length
-            if nlh.nlmsg_len - NLMSG_LENGTH(sizeof(nlmsg)) < 0:
-                raise RtNetlinkError("invalid nl length")
-
-            self._cbs[nlh.nlmsg_type](nlh, nlmsg)
-
-    def bind(self, groups, cbs):
-        self._cbs = cbs
-        Netlink.bind(self, groups, self._nl_cb)
-
-    def request(self, nlmsg_type, flags, extra, rtas={}):
-
-        nlh = Nlmsghdr.from_buffer(self.sendbuf)
-        nlh_p = addressof(nlh)
-
-        seq = self.seq
-        pid = self.pid
-
-        nlh.nlmsg_len = NLMSG_HDRLEN()
-        nlh.nlmsg_type = nlmsg_type
-        nlh.nlmsg_flags = flags
-        nlh.nlmsg_pid = pid
-        nlh.nlmsg_seq = seq
-
-        nlmsg = self.nlmsg(nlh)
-
-        nlh.nlmsg_len += nlmsg.pack_extra(extra, nlh_p + nlh.nlmsg_len)
-        nlh.nlmsg_len += nlmsg.pack_rtas_new(rtas, nlh_p + nlh.nlmsg_len,
-                                             nlmsg.rta_policy())
-        #self.dump(nlh)
-        self.sendall(string_at(nlh_p, nlh.nlmsg_len))
-        self.seq += 1
-
-        token = (pid, seq)
-        return token
diff --git a/ifupdown2/ifupdown/rtnetlink_api.py b/ifupdown2/ifupdown/rtnetlink_api.py
deleted file mode 100644 (file)
index f9bba10..0000000
+++ /dev/null
@@ -1,237 +0,0 @@
-#!/usr/bin/env python
-#
-# Copyright 2014 Cumulus Networks, Inc. All rights reserved.
-#
-# Author: Roopa Prabhu, roopa@cumulusnetworks.com
-#
-#
-
-from os import getpid
-from socket import AF_UNSPEC
-from socket import AF_BRIDGE
-from iff import IFF_UP
-from rtnetlink import *
-import os
-import ifupdownmain
-
-class rtnetlinkApi(RtNetlink):
-
-    bind_done = False
-
-    def __init__(self, pid):
-        RtNetlink.__init__(self, pid)
-        self.logger = logging.getLogger('ifupdown.' +
-                            self.__class__.__name__)
-        self.bind(0, None)
-        self.bind_done = True
-        self.ifindexmap = {}
-
-    def do_bind(self):
-        if self.bind_done:
-            return True
-        self.bind(0, None)
-        self.bind_done = True
-
-    def get_ifindex(self, ifname):
-        ifindex = self.ifindexmap.get(ifname)
-        if not ifindex:
-            with open('/sys/class/net/%s/ifindex' %ifname, 'r') as f:
-                ifindex = int(f.read())
-                self.ifindexmap[ifname] = ifindex
-        return ifindex
-
-    def create_vlan(self, link, ifname, vlanid):
-        self.logger.info('rtnetlink: creating vlan interface %s' %ifname)
-        if ifupdownmain.ifupdownFlags.DRYRUN:
-            return
-        try:
-            ifindex = self.get_ifindex(link)
-        except Exception, e:
-            raise Exception('cannot determine ifindex for link %s (%s)'
-                            %(link, str(e)))
-
-        ifm = Ifinfomsg(AF_UNSPEC)
-        rtas = {IFLA_IFNAME: ifname,
-                    IFLA_LINK : ifindex,
-                           IFLA_LINKINFO : {
-                                   IFLA_INFO_KIND : 'vlan',
-                                   IFLA_INFO_DATA : {
-                            IFLA_VLAN_ID : vlanid,
-                        }
-                    }
-               }
-        token = self.request(RTM_NEWLINK,
-                        NLM_F_CREATE | NLM_F_REQUEST | NLM_F_ACK, ifm, rtas)
-        self.process_wait([token])
-
-    def create_macvlan(self, ifname, link, mode='private'):
-        self.logger.info('rtnetlink: creating macvlan interface %s' %ifname)
-        if ifupdownmain.ifupdownFlags.DRYRUN:
-            return
-        try:
-            ifindex = self.get_ifindex(link)
-        except Exception, e:
-            raise Exception('cannot determine ifindex for link %s (%s)'
-                            %(link, str(e)))
-
-        ifm = Ifinfomsg(AF_UNSPEC)
-        rtas = {IFLA_IFNAME: ifname,
-                    IFLA_LINK : ifindex,
-                           IFLA_LINKINFO : {
-                                   IFLA_INFO_KIND : 'macvlan',
-                           IFLA_INFO_DATA : {
-                           IFLA_MACVLAN_MODE : MACVLAN_MODE_PRIVATE,
-                        }
-                    }
-               }
-        token = self.request(RTM_NEWLINK, NLM_F_CREATE | NLM_F_REQUEST |
-                             NLM_F_ACK, ifm, rtas)
-        self.process_wait([token])
-
-    def link_set(self, ifname, state):
-        flags = 0
-        self.logger.info('rtnetlink: setting link %s %s' %(ifname, state))
-        if ifupdownmain.ifupdownFlags.DRYRUN:
-            return
-
-        if state == "up":
-            flags |= IFF_UP
-        else:
-            flags &= ~IFF_UP
-
-        ifm = Ifinfomsg(AF_UNSPEC, ifi_change=IFF_UP, ifi_flags=flags)
-        rtas = {IFLA_IFNAME: ifname}
-
-        token = self.request(RTM_NEWLINK, NLM_F_REQUEST | NLM_F_ACK, ifm, rtas)
-        self.process_wait([token])
-
-    def link_set_hwaddress(self, ifname, hwaddress):
-        flags = 0
-        self.logger.info('rtnetlink: setting link hwaddress %s %s' %(ifname, hwaddress))
-        if ifupdownmain.ifupdownFlags.DRYRUN:
-            return
-
-        flags &= ~IFF_UP
-        ifm = Ifinfomsg(AF_UNSPEC, ifi_change=IFF_UP)
-        rtas = {IFLA_IFNAME: ifname,
-                IFLA_ADDRESS : str(bytearray([int(a,16) for a in hwaddress.split(':')]))}
-
-        self.logger.info(rtas)
-
-        token = self.request(RTM_NEWLINK, NLM_F_REQUEST | NLM_F_ACK, ifm, rtas)
-        self.process_wait([token])
-
-    def addr_add(self, ifname, address, broadcast=None, peer=None, scope=None,
-                 preferred_lifetime=None):
-        self.logger.info('rtnetlink: setting address')
-        if ifupdownmain.ifupdownFlags.DRYRUN:
-            return
-
-        try:
-            ifindex = self.get_ifindex(link)
-        except Exception, e:
-            raise Exception('cannot determine ifindex for link %s (%s)'
-                            %(link, str(e)))
-        ifa_scope = RT_SCOPE_
-        if scope:
-            if scope == "universe":
-                ifa_scope = RT_SCOPE_UNIVERSE
-            elif scope == "site":
-                ifa_scope = RT_SCOPE_SITE
-            elif scope == "link":
-                ifa_scope = RT_SCOPE_LINK
-            elif scope == "host":
-                ifa_scope = RT_SCOPE_HOST
-            elif scope == "nowhere":
-                ifa_scope = RT_SCOPE_NOWHERE
-        rtas = {IFLA_ADDRESS: ifname}
-
-        ifa = Ifaddrmsg(AF_UNSPEC, ifa_scope=ifa_scope, ifa_index=ifindex)
-
-        token = self.request(RTM_NEWADDR, NLM_F_REQUEST | NLM_F_ACK, ifa, rtas)
-        self.process_wait([token])
-
-    def link_set_many(self, ifname, ifattrs):
-        _ifattr_to_rta_map = {'dev' : IFLA_NAME,
-                              'address' : IFLA_ADDRESS,
-                              'broadcast' : IFLA_BROADCAST,
-                              'mtu' : IFLA_MTU,
-                              'master' : IFLA_MASTER}
-        flags = 0
-        ifi_change = IFF_UP
-        rtas = {}
-        self.logger.info('rtnetlink: setting link %s %s' %(ifname, state))
-        if ifupdownmain.ifupdownFlags.DRYRUN:
-            return
-        if not ifattrs:
-           return
-        state = ifattrs.get('state')
-        if state == 'up':
-            flags |= IFF_UP
-        elif state == 'down':
-            flags &= ~IFF_UP
-        else:
-            ifi_change = 0
-
-        if ifi_change:
-           ifm = Ifinfomsg(AF_UNSPEC, ifi_change=IFF_UP, ifi_flags=flags)
-        else:
-           ifm = Ifinfomsg(AF_UNSPEC)
-
-        for attr, attrval in ifattrs.items():
-            rta_attr = _ifattr_to_rta_map.get(attr)
-            if rta_attr:
-               if attr == 'hwaddress':
-                  rtas[rta_attr] = str(bytearray([int(a,16) for a in attrval.split(':')]))
-               else:
-                  rtas[rta_attr] = attrval
-
-        token = self.request(RTM_NEWLINK, NLM_F_REQUEST | NLM_F_ACK, ifm, rtas)
-        self.process_wait([token])
-
-    def bridge_vlan(self, add=True, vid=None, dev=None, pvid=False,
-                    untagged=False, master=True):
-        flags = 0
-        vflags = 0
-        if not vid or not dev:
-           return
-        self.logger.info('rtnetlink: bridge vlan add vid %s %s %s dev %s %s'
-                         %(vid, 'untagged' if untagged else '',
-                           'pvid' if pvid else '', dev,
-                           'self' if self else ''))
-        if ifupdownmain.ifupdownFlags.DRYRUN:
-            return
-        try:
-            ifindex = self.get_ifindex(dev)
-        except Exception, e:
-            raise Exception('cannot determine ifindex for dev %s (%s)'
-                            %(dev, str(e)))
-        if not master:
-            flags = BRIDGE_FLAGS_SELF
-
-        if pvid:
-           vflags = BRIDGE_VLAN_INFO_PVID
-           vflags |= BRIDGE_VLAN_INFO_UNTAGGED
-        elif untagged:
-           vflags |= BRIDGE_VLAN_INFO_UNTAGGED
-
-        ifm = Ifinfomsg(AF_BRIDGE, ifi_index=ifindex)
-        rtas = {IFLA_AF_SPEC: {
-                    IFLA_BRIDGE_FLAGS: flags,
-                    IFLA_BRIDGE_VLAN_INFO : BridgeVlanInfo(vflags, int(vid), int(vid))
-                  }
-               }
-        if add:
-            token = self.request(RTM_SETLINK,
-                        NLM_F_REQUEST | NLM_F_ACK, ifm, rtas)
-        else:
-            token = self.request(RTM_DELLINK,
-                        NLM_F_REQUEST | NLM_F_ACK, ifm, rtas)
-        self.process_wait([token])
-
-    def bridge_vlan_many(self, add=True, vids=[], dev=None, pvid=False,
-                         untagged=False, master=True):
-        for v in vids:
-            self.bridge_vlan_add(add, v, dev, ispvid, isuntagged, master)
-
-rtnl_api = rtnetlinkApi(os.getpid())
diff --git a/ifupdown2/ifupdown/scheduler.py b/ifupdown2/ifupdown/scheduler.py
deleted file mode 100644 (file)
index af9f28c..0000000
+++ /dev/null
@@ -1,531 +0,0 @@
-#!/usr/bin/python
-#
-# Copyright 2014 Cumulus Networks, Inc. All rights reserved.
-# Author: Roopa Prabhu, roopa@cumulusnetworks.com
-#
-# ifaceScheduler --
-#    interface scheduler
-#
-
-from statemanager import *
-from iface import *
-from graph import *
-from collections import deque
-from collections import OrderedDict
-import logging
-import traceback
-import sys
-from graph import *
-from collections import deque
-from threading import *
-from ifupdownbase import *
-from sets import Set
-
-class ifaceSchedulerFlags():
-    """ Enumerates scheduler flags """
-
-    INORDER = 0x1
-    POSTORDER = 0x2
-
-class ifaceScheduler():
-    """ scheduler functions to schedule configuration of interfaces.
-
-    supports scheduling of interfaces serially in plain interface list
-    or dependency graph format.
-
-    """
-
-    _STATE_CHECK = True
-
-    _SCHED_RETVAL = True
-
-    @classmethod
-    def run_iface_op(cls, ifupdownobj, ifaceobj, op, cenv=None):
-        """ Runs sub operation on an interface """
-        ifacename = ifaceobj.name
-
-        if ifupdownobj.type and ifupdownobj.type != ifaceobj.type:
-            return
-
-        if not ifupdownobj.ADDONS_ENABLE: return
-        if op == 'query-checkcurr':
-            query_ifaceobj=ifupdownobj.create_n_save_ifaceobjcurr(ifaceobj)
-            # If not type bridge vlan and the object does not exist,
-            # mark not found and return
-            if (not ifupdownobj.link_exists(ifaceobj.name) and
-                ifaceobj.type != ifaceType.BRIDGE_VLAN):
-                query_ifaceobj.set_state_n_status(ifaceState.from_str(op),
-                                                  ifaceStatus.NOTFOUND)
-                return
-        for mname in ifupdownobj.module_ops.get(op):
-            m = ifupdownobj.modules.get(mname)
-            err = 0
-            try:
-                if hasattr(m, 'run'):
-                    msg = ('%s: %s : running module %s' %(ifacename, op, mname))
-                    if op == 'query-checkcurr':
-                        # Dont check curr if the interface object was 
-                        # auto generated
-                        if (ifaceobj.priv_flags & ifupdownobj.NOCONFIG):
-                            continue
-                        ifupdownobj.logger.debug(msg)
-                        m.run(ifaceobj, op, query_ifaceobj,
-                              ifaceobj_getfunc=ifupdownobj.get_ifaceobjs)
-                    else:
-                        ifupdownobj.logger.debug(msg)
-                        m.run(ifaceobj, op,
-                              ifaceobj_getfunc=ifupdownobj.get_ifaceobjs)
-            except Exception, e:
-                if not ifupdownobj.ignore_error(str(e)):
-                   err = 1
-                   ifupdownobj.logger.warn(str(e))
-                # Continue with rest of the modules
-                pass
-            finally:
-                if err or ifaceobj.status == ifaceStatus.ERROR:
-                    ifaceobj.set_state_n_status(ifaceState.from_str(op),
-                                                ifaceStatus.ERROR)
-                    if 'up' in  op or 'down' in op:
-                        cls._SCHED_RETVAL = False
-                else:
-                    # Mark success only if the interface was not already
-                    # marked with error
-                    status = (ifaceobj.status
-                              if ifaceobj.status == ifaceStatus.ERROR
-                              else ifaceStatus.SUCCESS)
-                    ifaceobj.set_state_n_status(ifaceState.from_str(op),
-                                                status)
-
-        if ifupdownobj.config.get('addon_scripts_support', '0') == '1':
-            # execute /etc/network/ scripts 
-            for mname in ifupdownobj.script_ops.get(op, []):
-                ifupdownobj.logger.debug('%s: %s : running script %s'
-                    %(ifacename, op, mname))
-                try:
-                    ifupdownobj.exec_command(mname, cmdenv=cenv)
-                except Exception, e:
-                    ifupdownobj.log_error(str(e))
-
-    @classmethod
-    def run_iface_list_ops(cls, ifupdownobj, ifaceobjs, ops):
-        """ Runs all operations on a list of interface
-            configurations for the same interface
-        """
-
-        # minor optimization. If operation is 'down', proceed only
-        # if interface exists in the system
-        ifacename = ifaceobjs[0].name
-        ifupdownobj.logger.info('%s: running ops ...' %ifacename)
-        if ('down' in ops[0] and
-                ifaceobjs[0].type != ifaceType.BRIDGE_VLAN and
-                not ifupdownobj.link_exists(ifacename)):
-            ifupdownobj.logger.debug('%s: does not exist' %ifacename)
-            # run posthook before you get out of here, so that
-            # appropriate cleanup is done
-            posthookfunc = ifupdownobj.sched_hooks.get('posthook')
-            if posthookfunc:
-                for ifaceobj in ifaceobjs:
-                    ifaceobj.status = ifaceStatus.SUCCESS
-                    posthookfunc(ifupdownobj, ifaceobj, 'down')
-            return 
-        for op in ops:
-            # first run ifupdownobj handlers. This is good enough
-            # for the first object in the list
-            handler = ifupdownobj.ops_handlers.get(op)
-            if handler:
-                try:
-                    handler(ifupdownobj, ifaceobjs[0])
-                except Exception, e:
-                    if not ifupdownobj.link_master_slave_ignore_error(str(e)):
-                       ifupdownobj.logger.warn('%s: %s'
-                                   %(ifaceobjs[0].name, str(e)))
-                    pass
-            for ifaceobj in ifaceobjs:
-                cls.run_iface_op(ifupdownobj, ifaceobj, op,
-                    cenv=ifupdownobj.generate_running_env(ifaceobj, op)
-                        if ifupdownobj.config.get('addon_scripts_support',
-                            '0') == '1' else None)
-        posthookfunc = ifupdownobj.sched_hooks.get('posthook')
-        if posthookfunc:
-            try:
-                [posthookfunc(ifupdownobj, ifaceobj, ops[0])
-                    for ifaceobj in ifaceobjs]
-            except Exception, e:
-                ifupdownobj.logger.warn('%s' %str(e))
-                pass
-
-    @classmethod
-    def _check_upperifaces(cls, ifupdownobj, ifaceobj, ops, parent,
-                           followdependents=False):
-        """ Check if upperifaces are hanging off us and help caller decide
-        if he can proceed with the ops on this device
-
-        Returns True or False indicating the caller to proceed with the
-        operation.
-        """
-        # proceed only for down operation
-        if 'down' not in ops[0]:
-            return True
-
-        if (ifupdownobj.FORCE or
-                not ifupdownobj.ADDONS_ENABLE or
-                (not ifupdownobj.is_ifaceobj_noconfig(ifaceobj) and
-                ifupdownobj.config.get('warn_on_ifdown', '0') == '0' and
-                not ifupdownobj.ALL)):
-            return True
-
-        ulist = ifaceobj.upperifaces
-        if not ulist:
-            return True
-
-        # Get the list of upper ifaces other than the parent
-        tmpulist = ([u for u in ulist if u != parent] if parent
-                    else ulist)
-        if not tmpulist:
-            return True
-        # XXX: This is expensive. Find a cheaper way to do this.
-        # if any of the upperdevs are present,
-        # return false to the caller to skip this interface
-        for u in tmpulist:
-            if ifupdownobj.link_exists(u):
-                if not ifupdownobj.ALL:
-                    if ifupdownobj.is_ifaceobj_noconfig(ifaceobj):
-                        ifupdownobj.logger.info('%s: skipping interface down,'
-                            %ifaceobj.name + ' upperiface %s still around ' %u)
-                    else:
-                        ifupdownobj.logger.warn('%s: skipping interface down,'
-                            %ifaceobj.name + ' upperiface %s still around ' %u)
-                return False
-        return True
-
-    @classmethod
-    def run_iface_graph(cls, ifupdownobj, ifacename, ops, parent=None,
-                        order=ifaceSchedulerFlags.POSTORDER,
-                        followdependents=True):
-        """ runs interface by traversing all nodes rooted at itself """
-
-        # Each ifacename can have a list of iface objects
-        ifaceobjs = ifupdownobj.get_ifaceobjs(ifacename)
-        if not ifaceobjs:
-            raise Exception('%s: not found' %ifacename)
-
-        # Check state of the dependent. If it is already brought up, return
-        if (cls._STATE_CHECK and
-            (ifaceobjs[0].state == ifaceState.from_str(ops[-1]))):
-            ifupdownobj.logger.debug('%s: already processed' %ifacename)
-            return
-
-        for ifaceobj in ifaceobjs:
-            if not cls._check_upperifaces(ifupdownobj, ifaceobj,
-                                          ops, parent, followdependents):
-               return
-
-        # If inorder, run the iface first and then its dependents
-        if order == ifaceSchedulerFlags.INORDER:
-            cls.run_iface_list_ops(ifupdownobj, ifaceobjs, ops)
-
-        for ifaceobj in ifaceobjs:
-            # Run lowerifaces or dependents
-            dlist = ifaceobj.lowerifaces
-            if dlist:
-                ifupdownobj.logger.debug('%s: found dependents %s'
-                            %(ifacename, str(dlist)))
-                try:
-                    if not followdependents:
-                        # XXX: this is yet another extra step,
-                        # but is needed for interfaces that are
-                        # implicit dependents. even though we are asked to
-                        # not follow dependents, we must follow the ones
-                        # that dont have user given config. Because we own them
-                        new_dlist = [d for d in dlist
-                                    if ifupdownobj.is_iface_noconfig(d)]
-                        if new_dlist:
-                            cls.run_iface_list(ifupdownobj, new_dlist, ops,
-                                           ifacename, order, followdependents,
-                                           continueonfailure=False)
-                    else:
-                        cls.run_iface_list(ifupdownobj, dlist, ops,
-                                            ifacename, order,
-                                            followdependents,
-                                            continueonfailure=False)
-                except Exception, e:
-                    if (ifupdownobj.ignore_error(str(e))):
-                        pass
-                    else:
-                        # Dont bring the iface up if children did not come up
-                        ifaceobj.set_state_n_status(ifaceState.NEW,
-                                                ifaceStatus.ERROR)
-                        raise
-        if order == ifaceSchedulerFlags.POSTORDER:
-            cls.run_iface_list_ops(ifupdownobj, ifaceobjs, ops)
-
-    @classmethod
-    def run_iface_list(cls, ifupdownobj, ifacenames,
-                       ops, parent=None, order=ifaceSchedulerFlags.POSTORDER,
-                       followdependents=True, continueonfailure=True):
-        """ Runs interface list """
-
-        for ifacename in ifacenames:
-            try:
-              cls.run_iface_graph(ifupdownobj, ifacename, ops, parent,
-                      order, followdependents)
-            except Exception, e:
-                if continueonfailure:
-                    if ifupdownobj.logger.isEnabledFor(logging.DEBUG):
-                        traceback.print_tb(sys.exc_info()[2])
-                    ifupdownobj.logger.error('%s : %s' %(ifacename, str(e)))
-                    pass
-                else:
-                    if (ifupdownobj.ignore_error(str(e))):
-                        pass
-                    else:
-                        raise Exception('%s : (%s)' %(ifacename, str(e)))
-
-    @classmethod
-    def run_iface_graph_upper(cls, ifupdownobj, ifacename, ops, parent=None,
-                        followdependents=True, skip_root=False):
-        """ runs interface by traversing all nodes rooted at itself """
-
-        # Each ifacename can have a list of iface objects
-        ifaceobjs = ifupdownobj.get_ifaceobjs(ifacename)
-        if not ifaceobjs:
-            raise Exception('%s: not found' %ifacename)
-
-        if (cls._STATE_CHECK and
-            (ifaceobjs[0].state == ifaceState.from_str(ops[-1]))):
-            ifupdownobj.logger.debug('%s: already processed' %ifacename)
-            return
-
-        if not skip_root:
-            # run the iface first and then its upperifaces
-            cls.run_iface_list_ops(ifupdownobj, ifaceobjs, ops)
-        for ifaceobj in ifaceobjs:
-            # Run upperifaces
-            ulist = ifaceobj.upperifaces
-            if ulist:
-                ifupdownobj.logger.debug('%s: found upperifaces %s'
-                                            %(ifacename, str(ulist)))
-                try:
-                    cls.run_iface_list_upper(ifupdownobj, ulist, ops,
-                                            ifacename,
-                                            followdependents,
-                                            continueonfailure=True)
-                except Exception, e:
-                    if (ifupdownobj.ignore_error(str(e))):
-                        pass
-                    else:
-                        raise
-
-    @classmethod
-    def run_iface_list_upper(cls, ifupdownobj, ifacenames,
-                       ops, parent=None, followdependents=True,
-                       continueonfailure=True, skip_root=False):
-        """ Runs interface list """
-
-        for ifacename in ifacenames:
-            try:
-              cls.run_iface_graph_upper(ifupdownobj, ifacename, ops, parent,
-                      followdependents, skip_root)
-            except Exception, e:
-                if ifupdownobj.logger.isEnabledFor(logging.DEBUG):
-                    traceback.print_tb(sys.exc_info()[2])
-                ifupdownobj.logger.warn('%s : %s' %(ifacename, str(e)))
-                pass
-
-    @classmethod
-    def _get_valid_upperifaces(cls, ifupdownobj, ifacenames,
-                               allupperifacenames):
-        """ Recursively find valid upperifaces
-
-        valid upperifaces are:
-            - An upperiface which had no user config (example builtin
-              interfaces. usually vlan interfaces.)
-            - or had config and previously up
-            - and interface currently does not exist
-            - or is a bridge (because if your upperiface was a bridge
-            - u will have to execute up on the bridge
-              to enslave the port and apply bridge attributes to the port) """
-
-        upperifacenames = []
-        for ifacename in ifacenames:
-            # get upperifaces
-            ifaceobj = ifupdownobj.get_ifaceobj_first(ifacename)
-            if not ifaceobj:
-               continue
-            ulist = Set(ifaceobj.upperifaces).difference(upperifacenames)
-            nulist = []
-            for u in ulist:
-                uifaceobj = ifupdownobj.get_ifaceobj_first(u)
-                if not uifaceobj:
-                   continue
-                has_config = not bool(uifaceobj.priv_flags
-                                   & ifupdownobj.NOCONFIG)
-                if (((has_config and ifupdownobj.get_ifaceobjs_saved(u)) or
-                     not has_config) and (not ifupdownobj.link_exists(u)
-                         or uifaceobj.link_kind == ifaceLinkKind.BRIDGE)):
-                     nulist.append(u)
-            upperifacenames.extend(nulist)
-        allupperifacenames.extend(upperifacenames)
-        if upperifacenames:
-            cls._get_valid_upperifaces(ifupdownobj, upperifacenames,
-                                       allupperifacenames)
-        return
-
-    @classmethod
-    def run_upperifaces(cls, ifupdownobj, ifacenames, ops,
-                        continueonfailure=True):
-        """ Run through valid upperifaces """ 
-        upperifaces = []
-
-        cls._get_valid_upperifaces(ifupdownobj, ifacenames, upperifaces)
-        if not upperifaces:
-           return
-        # dump valid upperifaces
-        ifupdownobj.logger.debug(upperifaces)
-        for u in upperifaces:
-            try:
-                ifaceobjs = ifupdownobj.get_ifaceobjs(u)
-                if not ifaceobjs:
-                   continue
-                cls.run_iface_list_ops(ifupdownobj, ifaceobjs, ops)
-            except Exception, e:
-                if continueonfailure:
-                   self.logger.warn('%s' %str(e))
-
-    @classmethod
-    def get_sorted_iface_list(cls, ifupdownobj, ifacenames, ops,
-                              dependency_graph, indegrees=None):
-        if len(ifacenames) == 1:
-            return ifacenames
-        # Get a sorted list of all interfaces
-        if not indegrees:
-            indegrees = OrderedDict()
-            for ifacename in dependency_graph.keys():
-                indegrees[ifacename] = ifupdownobj.get_iface_refcnt(ifacename)
-        ifacenames_all_sorted = graph.topological_sort_graphs_all(
-                                        dependency_graph, indegrees)
-        # if ALL was set, return all interfaces
-        if ifupdownobj.ALL:
-            return ifacenames_all_sorted
-
-        # else return ifacenames passed as argument in sorted order
-        ifacenames_sorted = []
-        [ifacenames_sorted.append(ifacename)
-                        for ifacename in ifacenames_all_sorted
-                            if ifacename in ifacenames]
-        return ifacenames_sorted
-
-    @classmethod
-    def sched_ifaces(cls, ifupdownobj, ifacenames, ops,
-                dependency_graph=None, indegrees=None,
-                order=ifaceSchedulerFlags.POSTORDER,
-                followdependents=True, skipupperifaces=False, sort=False):
-        """ runs interface configuration modules on interfaces passed as
-            argument. Runs topological sort on interface dependency graph.
-
-        Args:
-            **ifupdownobj** (object): ifupdownMain object 
-
-            **ifacenames** (list): list of interface names
-
-            **ops** : list of operations to perform eg ['pre-up', 'up', 'post-up']
-
-            **dependency_graph** (dict): dependency graph in adjacency list format
-
-        Kwargs:
-            **indegrees** (dict): indegree array of the dependency graph
-
-            **order** (int): ifaceSchedulerFlags (POSTORDER, INORDER)
-
-            **followdependents** (bool): follow dependent interfaces if true
-
-            **sort** (bool): sort ifacelist in the case where ALL is not set
-
-        """
-        #
-        # Algo:
-        # if ALL/auto interfaces are specified,
-        #   - walk the dependency tree in postorder or inorder depending
-        #     on the operation.
-        #     (This is to run interfaces correctly in order)
-        # else:
-        #   - sort iface list if the ifaces belong to a "class"
-        #   - else just run iface list in the order they were specified
-        #
-        # Run any upperifaces if available
-        #
-        followupperifaces = False
-        run_queue = []
-        skip_ifacesort = int(ifupdownobj.config.get('skip_ifacesort', '0'))
-        if not skip_ifacesort and not indegrees:
-            indegrees = OrderedDict()
-            for ifacename in dependency_graph.keys():
-                indegrees[ifacename] = ifupdownobj.get_iface_refcnt(ifacename)
-
-        if not ifupdownobj.ALL:
-            if 'up' in ops[0]:
-                # If there is any interface that does not exist, maybe it
-                # is a logical interface and we have to followupperifaces
-                # when it comes up, so lets get that list.
-                if any([True for i in ifacenames
-                        if ifupdownobj.must_follow_upperifaces(i)]):
-                    followupperifaces = (True if
-                                    [i for i in ifacenames
-                                        if not ifupdownobj.link_exists(i)]
-                                        else False)
-            # sort interfaces only if the caller asked to sort
-            # and skip_ifacesort is not on.
-            if not skip_ifacesort and sort:
-                run_queue = cls.get_sorted_iface_list(ifupdownobj, ifacenames,
-                                    ops, dependency_graph, indegrees)
-                if run_queue and 'up' in ops[0]:
-                    run_queue.reverse()
-        else:
-            # if -a is set, we pick the interfaces
-            # that have no parents and use a sorted list of those
-            if not skip_ifacesort:
-                sorted_ifacenames = cls.get_sorted_iface_list(ifupdownobj,
-                                            ifacenames, ops, dependency_graph,
-                                            indegrees)
-                if sorted_ifacenames:
-                    # pick interfaces that user asked
-                    # and those that dont have any dependents first
-                    [run_queue.append(ifacename)
-                        for ifacename in sorted_ifacenames
-                            if ifacename in ifacenames and
-                            not indegrees.get(ifacename)]
-                    ifupdownobj.logger.debug('graph roots (interfaces that ' +
-                            'dont have dependents):' + ' %s' %str(run_queue))
-                else:
-                    ifupdownobj.logger.warn('interface sort returned None')
-
-        # If queue not present, just run interfaces that were asked by the
-        # user
-        if not run_queue:
-            run_queue = list(ifacenames)
-            # if we are taking the order of interfaces as specified
-            # in the interfaces file, we should reverse the list if we
-            # want to down. This can happen if 'skip_ifacesort'
-            # is been specified.
-            if 'down' in ops[0]:
-                run_queue.reverse()
-
-        # run interface list
-        cls.run_iface_list(ifupdownobj, run_queue, ops,
-                           parent=None, order=order,
-                           followdependents=followdependents)
-        if not cls._SCHED_RETVAL:
-            raise Exception()
-
-        if (not skipupperifaces and
-                ifupdownobj.config.get('skip_upperifaces', '0') == '0' and
-                ((not ifupdownobj.ALL and followdependents) or
-                followupperifaces) and
-                'up' in ops[0]):
-            # If user had given a set of interfaces to bring up
-            # try and execute 'up' on the upperifaces
-            ifupdownobj.logger.info('running upperifaces (parent interfaces) ' +
-                                    'if available ..')
-            cls._STATE_CHECK = False
-            cls.run_upperifaces(ifupdownobj, ifacenames, ops)
-            cls._STATE_CHECK = True
diff --git a/ifupdown2/ifupdown/scheduler.py.orig b/ifupdown2/ifupdown/scheduler.py.orig
deleted file mode 100644 (file)
index 99cc9a8..0000000
+++ /dev/null
@@ -1,429 +0,0 @@
-#!/usr/bin/python
-#
-# Copyright 2013.  Cumulus Networks, Inc.
-# Author: Roopa Prabhu, roopa@cumulusnetworks.com
-#
-# ifaceScheduler --
-#    interface scheduler
-#
-
-from statemanager import *
-from iface import *
-from graph import *
-from collections import deque
-from collections import OrderedDict
-import logging
-import traceback
-import sys
-from graph import *
-from collections import deque
-from threading import *
-from ifupdownbase import *
-
-class ifaceSchedulerFlags():
-    INORDER = 0x1
-    POSTORDER = 0x2
-
-class ifaceScheduler():
-    """ scheduler functions to schedule configuration of interfaces.
-
-    supports scheduling of interfaces serially in plain interface list
-    or dependency graph format.
-
-    Algo:
-        - run topological sort on the iface objects
-        - In the sorted iface object list, pick up interfaces with no parents
-        and run ops on them and their children. 
-        - If operation is up and user gave interface list (ie not all)
-        option, also see if there were upper-devices and run ops on them. 
-        - if operation is down, dont down the interface if it still
-        has upperifaces present. The down operation is executed when the
-        last upperiface goes away. If force option is set, this rule does not
-        apply.
-        - run ops calls addon modules run operation passing the iface
-        object and op to each module.
-        - ops are [pre-up, up, post-up, pre-down, down,
-                   post-down, query-running, query-check]
-    """
-
-    _STATE_CHECK = True
-
-    _SCHED_RETVAL = True
-
-    @classmethod
-    def run_iface_op(cls, ifupdownobj, ifaceobj, op, cenv=None):
-        """ Runs sub operation on an interface """
-        ifacename = ifaceobj.name
-
-        if (cls._STATE_CHECK and
-            (ifaceobj.state >= ifaceState.from_str(op))):
-            ifupdownobj.logger.debug('%s: already in state %s' %(ifacename, op))
-            return
-        if not ifupdownobj.ADDONS_ENABLE: return
-        if op == 'query-checkcurr':
-            query_ifaceobj=ifupdownobj.create_n_save_ifaceobjcurr(ifaceobj)
-        for mname in ifupdownobj.module_ops.get(op):
-            m = ifupdownobj.modules.get(mname)
-            err = 0
-            try:
-                if hasattr(m, 'run'):
-                    msg = ('%s: %s : running module %s' %(ifacename, op, mname))
-                    if op == 'query-checkcurr':
-                        # Dont check curr if the interface object was 
-                        # auto generated
-                        if (ifaceobj.priv_flags & ifupdownobj.NOCONFIG):
-                            continue
-                        ifupdownobj.logger.debug(msg)
-                        m.run(ifaceobj, op, query_ifaceobj)
-                    else:
-                        ifupdownobj.logger.debug(msg)
-                        m.run(ifaceobj, op)
-            except Exception, e:
-                err = 1
-                ifupdownobj.log_error(str(e))
-                err = 0  # error can be ignored by log_error, in which case
-                         # reset err flag
-            finally:
-                if err or ifaceobj.status == ifaceStatus.ERROR:
-                    ifaceobj.set_state_n_status(ifaceState.from_str(op),
-                                                ifaceStatus.ERROR)
-                    if 'up' in  op or 'down' in op:
-                        cls._SCHED_RETVAL = False
-                else:
-                    ifaceobj.set_state_n_status(ifaceState.from_str(op),
-                                                ifaceStatus.SUCCESS)
-
-        if ifupdownobj.COMPAT_EXEC_SCRIPTS:
-            # execute /etc/network/ scripts 
-            for mname in ifupdownobj.script_ops.get(op, []):
-                ifupdownobj.logger.debug('%s: %s : running script %s'
-                    %(ifacename, op, mname))
-                try:
-                    ifupdownobj.exec_command(mname, cmdenv=cenv)
-                except Exception, e:
-                    ifupdownobj.log_error(str(e))
-
-    @classmethod
-    def run_iface_list_ops(cls, ifupdownobj, ifaceobjs, ops):
-        """ Runs all operations on a list of interface
-            configurations for the same interface
-        """
-        # minor optimization. If operation is 'down', proceed only
-        # if interface exists in the system
-        ifacename = ifaceobjs[0].name
-        if ('down' in ops[0] and
-                not ifupdownobj.link_exists(ifacename)):
-            ifupdownobj.logger.debug('%s: does not exist' %ifacename)
-            # run posthook before you get out of here, so that
-            # appropriate cleanup is done
-            posthookfunc = ifupdownobj.sched_hooks.get('posthook')
-            if posthookfunc:
-                for ifaceobj in ifaceobjs:
-                    ifaceobj.status = ifaceStatus.SUCCESS
-                    posthookfunc(ifupdownobj, ifaceobj, 'down')
-            return 
-        for op in ops:
-            # first run ifupdownobj handlers. This is good enough
-            # for the first object in the list
-            handler = ifupdownobj.ops_handlers.get(op)
-            if handler:
-                if (not ifaceobjs[0].addr_method or
-                    (ifaceobjs[0].addr_method and
-                    ifaceobjs[0].addr_method != 'manual')):
-                    handler(ifupdownobj, ifaceobjs[0])
-            for ifaceobj in ifaceobjs:
-                cls.run_iface_op(ifupdownobj, ifaceobj, op,
-                    cenv=ifupdownobj.generate_running_env(ifaceobj, op)
-                        if ifupdownobj.COMPAT_EXEC_SCRIPTS else None) 
-                posthookfunc = ifupdownobj.sched_hooks.get('posthook')
-                if posthookfunc:
-                    posthookfunc(ifupdownobj, ifaceobj, op)
-
-    @classmethod
-    def _check_upperifaces(cls, ifupdownobj, ifaceobj, ops, parent,
-                           followdependents=False):
-        """ Check if upperifaces are hanging off us and help caller decide
-        if he can proceed with the ops on this device
-
-        Returns True or False indicating the caller to proceed with the
-        operation.
-        """
-        # proceed only for down operation
-        if 'down' not in ops[0]:
-            return True
-
-        if (ifupdownobj.FORCE or
-                not ifupdownobj.ADDONS_ENABLE or
-                (not ifupdownobj.is_ifaceobj_noconfig(ifaceobj) and
-                ifupdownobj.config.get('warn_on_ifdown', '0') == '0' and
-                not ifupdownobj.ALL)):
-            return True
-
-        ulist = ifaceobj.upperifaces
-        if not ulist:
-            return True
-
-        # Get the list of upper ifaces other than the parent
-        tmpulist = ([u for u in ulist if u != parent] if parent
-                    else ulist)
-        if not tmpulist:
-            return True
-        # XXX: This is expensive. Find a cheaper way to do this.
-        # if any of the upperdevs are present,
-        # return false to the caller to skip this interface
-        for u in tmpulist:
-            if ifupdownobj.link_exists(u):
-                if not ifupdownobj.ALL:
-                    if ifupdownobj.is_ifaceobj_noconfig(ifaceobj):
-                        ifupdownobj.logger.info('%s: skipping interface down,'
-                            %ifaceobj.name + ' upperiface %s still around ' %u)
-                    else:
-                        ifupdownobj.logger.warn('%s: skipping interface down,'
-                            %ifaceobj.name + ' upperiface %s still around ' %u)
-                return False
-        return True
-
-    @classmethod
-    def run_iface_graph(cls, ifupdownobj, ifacename, ops, parent=None,
-                        order=ifaceSchedulerFlags.POSTORDER,
-                        followdependents=True):
-        """ runs interface by traversing all nodes rooted at itself """
-
-        # Each ifacename can have a list of iface objects
-        ifaceobjs = ifupdownobj.get_ifaceobjs(ifacename)
-        if not ifaceobjs:
-            raise Exception('%s: not found' %ifacename)
-
-        for ifaceobj in ifaceobjs:
-            if not cls._check_upperifaces(ifupdownobj, ifaceobj,
-                                          ops, parent, followdependents):
-                return
-
-        # If inorder, run the iface first and then its dependents
-        if order == ifaceSchedulerFlags.INORDER:
-            cls.run_iface_list_ops(ifupdownobj, ifaceobjs, ops)
-
-        for ifaceobj in ifaceobjs:
-            # Run lowerifaces or dependents
-            dlist = ifaceobj.lowerifaces
-            if dlist:
-                ifupdownobj.logger.debug('%s: found dependents %s'
-                            %(ifacename, str(dlist)))
-                try:
-                    if not followdependents:
-                        # XXX: this is yet another extra step,
-                        # but is needed for interfaces that are
-                        # implicit dependents. even though we are asked to
-                        # not follow dependents, we must follow the ones
-                        # that dont have user given config. Because we own them
-                        new_dlist = [d for d in dlist
-                                    if ifupdownobj.is_iface_noconfig(d)]
-                        if new_dlist:
-                            cls.run_iface_list(ifupdownobj, new_dlist, ops,
-                                           ifacename, order, followdependents,
-                                           continueonfailure=False)
-                    else:
-                        cls.run_iface_list(ifupdownobj, dlist, ops,
-                                            ifacename, order,
-                                            followdependents,
-                                            continueonfailure=False)
-                except Exception, e:
-                    if (ifupdownobj.ignore_error(str(e))):
-                        pass
-                    else:
-                        # Dont bring the iface up if children did not come up
-                        ifaceobj.set_state_n_status(ifaceState.NEW,
-                                                ifaceStatus.ERROR)
-                        raise
-        if order == ifaceSchedulerFlags.POSTORDER:
-            cls.run_iface_list_ops(ifupdownobj, ifaceobjs, ops)
-
-    @classmethod
-    def run_iface_list(cls, ifupdownobj, ifacenames,
-                       ops, parent=None, order=ifaceSchedulerFlags.POSTORDER,
-                       followdependents=True, continueonfailure=True):
-        """ Runs interface list """
-
-        for ifacename in ifacenames:
-            try:
-              cls.run_iface_graph(ifupdownobj, ifacename, ops, parent,
-                      order, followdependents)
-            except Exception, e:
-                if continueonfailure:
-                    if ifupdownobj.logger.isEnabledFor(logging.DEBUG):
-                        traceback.print_tb(sys.exc_info()[2])
-                    ifupdownobj.logger.error('%s : %s' %(ifacename, str(e)))
-                    pass
-                else:
-                    if (ifupdownobj.ignore_error(str(e))):
-                        pass
-                    else:
-                        raise Exception('%s : (%s)' %(ifacename, str(e)))
-
-    @classmethod
-    def run_iface_graph_upper(cls, ifupdownobj, ifacename, ops, parent=None,
-                        followdependents=True, skip_root=False):
-        """ runs interface by traversing all nodes rooted at itself """
-
-        # Each ifacename can have a list of iface objects
-        ifaceobjs = ifupdownobj.get_ifaceobjs(ifacename)
-        if not ifaceobjs:
-            raise Exception('%s: not found' %ifacename)
-
-        if not skip_root:
-            # run the iface first and then its upperifaces
-            cls.run_iface_list_ops(ifupdownobj, ifaceobjs, ops)
-        for ifaceobj in ifaceobjs:
-            # Run upperifaces
-            ulist = ifaceobj.upperifaces
-            if ulist:
-                ifupdownobj.logger.debug('%s: found upperifaces %s'
-                                            %(ifacename, str(ulist)))
-                try:
-                    cls.run_iface_list_upper(ifupdownobj, ulist, ops,
-                                            ifacename,
-                                            followdependents,
-                                            continueonfailure=True)
-                except Exception, e:
-                    if (ifupdownobj.ignore_error(str(e))):
-                        pass
-                    else:
-                        raise
-
-    @classmethod
-    def run_iface_list_upper(cls, ifupdownobj, ifacenames,
-                       ops, parent=None, followdependents=True,
-                       continueonfailure=True, skip_root=False):
-        """ Runs interface list """
-
-        for ifacename in ifacenames:
-            try:
-              cls.run_iface_graph_upper(ifupdownobj, ifacename, ops, parent,
-                      followdependents, skip_root)
-            except Exception, e:
-                if ifupdownobj.logger.isEnabledFor(logging.DEBUG):
-                    traceback.print_tb(sys.exc_info()[2])
-                ifupdownobj.logger.warn('%s : %s' %(ifacename, str(e)))
-                pass
-
-    @classmethod
-    def get_sorted_iface_list(cls, ifupdownobj, ifacenames, ops,
-                              dependency_graph, indegrees=None):
-        if len(ifacenames) == 1:
-            return ifacenames
-        # Get a sorted list of all interfaces
-        if not indegrees:
-            indegrees = OrderedDict()
-            for ifacename in dependency_graph.keys():
-                indegrees[ifacename] = ifupdownobj.get_iface_refcnt(ifacename)
-        ifacenames_all_sorted = graph.topological_sort_graphs_all(
-                                        dependency_graph, indegrees)
-        # if ALL was set, return all interfaces
-        if ifupdownobj.ALL:
-            return ifacenames_all_sorted
-
-        # else return ifacenames passed as argument in sorted order
-        ifacenames_sorted = []
-        [ifacenames_sorted.append(ifacename)
-                        for ifacename in ifacenames_all_sorted
-                            if ifacename in ifacenames]
-        return ifacenames_sorted
-
-    @classmethod
-    def sched_ifaces(cls, ifupdownobj, ifacenames, ops,
-                dependency_graph=None, indegrees=None,
-                order=ifaceSchedulerFlags.POSTORDER,
-                followdependents=True):
-        """ Runs iface dependeny graph by visiting all the nodes
-        
-        Parameters:
-        -----------
-        ifupdownobj : ifupdown object (used for getting and updating iface
-                                        object state)
-        dependency_graph : dependency graph in adjacency list
-                            format (contains more than one dependency graph)
-        ops : list of operations to perform eg ['pre-up', 'up', 'post-up']
-
-        indegrees : indegree array if present is used to topologically sort
-                    the graphs in the dependency_graph
-        """
-        #
-        # Algo:
-        # if ALL/auto interfaces are specified,
-        #   - walk the dependency tree in postorder or inorder depending
-        #     on the operation.
-        #     (This is to run interfaces correctly in order)
-        # else:
-        #   - sort iface list if the ifaces belong to a "class"
-        #   - else just run iface list in the order they were specified
-        #
-        # Run any upperifaces if available
-        #
-        followupperifaces = []
-        run_queue = []
-        skip_ifacesort = int(ifupdownobj.config.get('skip_ifacesort', '0'))
-        if not skip_ifacesort and not indegrees:
-            indegrees = OrderedDict()
-            for ifacename in dependency_graph.keys():
-                indegrees[ifacename] = ifupdownobj.get_iface_refcnt(ifacename)
-
-        if not ifupdownobj.ALL:
-            # If there is any interface that does exist, maybe it is a
-            # logical interface and we have to followupperifaces when it
-            # comes up, so get that list.
-            followupperifaces = (True if
-                                    [i for i in ifacenames
-                                        if not ifupdownobj.link_exists(i)]
-                                        else False)
-            if not skip_ifacesort and ifupdownobj.IFACE_CLASS:
-                # sort interfaces only if allow class was specified and
-                # not skip_ifacesort
-                run_queue = cls.get_sorted_iface_list(ifupdownobj, ifacenames,
-                                    ops, dependency_graph, indegrees)
-                if run_queue and 'up' in ops[0]:
-                    run_queue.reverse()
-        else:
-            # if -a is set, we dont really have to sort. We pick the interfaces
-            # that have no parents and 
-            if not skip_ifacesort:
-                sorted_ifacenames = cls.get_sorted_iface_list(ifupdownobj,
-                                            ifacenames, ops, dependency_graph,
-                                            indegrees)
-                if sorted_ifacenames:
-                    # pick interfaces that user asked
-                    # and those that dont have any dependents first
-                    [run_queue.append(ifacename)
-                        for ifacename in sorted_ifacenames
-                            if ifacename in ifacenames and
-                            not indegrees.get(ifacename)]
-                    ifupdownobj.logger.debug('graph roots (interfaces that ' +
-                            'dont have dependents):' + ' %s' %str(run_queue))
-                else:
-                    ifupdownobj.logger.warn('interface sort returned None')
-
-        # If queue not present, just run interfaces that were asked by the user
-        if not run_queue:
-            run_queue = list(ifacenames)
-            if 'down' in ops[0]:
-                run_queue.reverse()
-
-        # run interface list
-        ifupdownobj.logger.info('running interfaces: %s' %str(run_queue))
-        cls.run_iface_list(ifupdownobj, run_queue, ops,
-                           parent=None, order=order,
-                           followdependents=followdependents)
-        if not cls._SCHED_RETVAL:
-            raise Exception()
-
-        if (ifupdownobj.config.get('skip_upperifaces', '0') == '0' and
-                ((not ifupdownobj.ALL and followdependents) or
-                followupperifaces) and
-                'up' in ops[0]):
-            # If user had given a set of interfaces to bring up
-            # try and execute 'up' on the upperifaces
-            ifupdownobj.logger.info('running upperifaces (parent interfaces) ' +
-                                    'if available ..')
-            cls._STATE_CHECK = False
-            cls.run_iface_list_upper(ifupdownobj, ifacenames, ops,
-                                     skip_root=True)
-            cls._STATE_CHECK = True
diff --git a/ifupdown2/ifupdown/statemanager.py b/ifupdown2/ifupdown/statemanager.py
deleted file mode 100644 (file)
index ef9ca7f..0000000
+++ /dev/null
@@ -1,176 +0,0 @@
-#!/usr/bin/python
-#
-# Copyright 2014 Cumulus Networks, Inc. All rights reserved.
-# Author: Roopa Prabhu, roopa@cumulusnetworks.com
-#
-# stateManager --
-#    interface state manager
-#
-import cPickle
-from collections import OrderedDict
-import logging
-import os
-from iface import *
-
-class pickling():
-    """ class with helper methods for pickling/unpickling iface objects """
-
-    @classmethod
-    def save(cls, filename, list_of_objects):
-        """ pickle a list of iface objects """
-        try:
-            with open(filename, 'w') as f:
-                for obj in list_of_objects:
-                    cPickle.dump(obj, f, cPickle.HIGHEST_PROTOCOL)
-        except:
-            raise
-
-    @classmethod
-    def save_obj(cls, f, obj):
-        """ pickle iface object """
-        try:
-            cPickle.dump(obj, f, cPickle.HIGHEST_PROTOCOL)
-        except:
-            raise
-
-    @classmethod
-    def load(cls, filename):
-        """ load picked iface object """
-        with open(filename, 'r') as f:
-            while True:
-                try: yield cPickle.load(f)
-                except EOFError: break
-                except: raise
-
-class stateManager():
-    """ state manager for managing ifupdown iface obj state
-
-    ifupdown2 has to maitain old objects for down operation on
-    interfaces. ie to down or delete old configuration.
-
-    This class uses pickle to store iface objects.
-
-    """
-
-    state_dir = '/var/tmp/network/'
-    """directory where the state file is stored """
-
-    state_filename = 'ifstatenew'
-    """name of the satefile """
-
-    def __init__(self):
-        """ Initializes statemanager internal state
-
-        which includes a dictionary of last pickled iface objects
-        """
-        self.ifaceobjdict = OrderedDict()
-        self.logger = logging.getLogger('ifupdown.' +
-                    self.__class__.__name__)
-        if not os.path.exists(self.state_dir):
-            os.mkdir(self.state_dir)
-        self.state_file = self.state_dir + self.state_filename
-
-    def save_ifaceobj(self, ifaceobj):
-        self.ifaceobjdict.setdefault(ifaceobj.name,
-                            []).append(ifaceobj)
-
-    def read_saved_state(self, filename=None):
-        """This member function reads saved iface objects
-
-        Kwargs:
-            filename (str): name of the state file
-        """
-
-        pickle_filename = filename
-        if not pickle_filename:
-            pickle_filename = self.state_file
-        if not os.path.exists(pickle_filename):
-            return
-        for ifaceobj in pickling.load(pickle_filename):
-            self.save_ifaceobj(ifaceobj)
-
-    def get_ifaceobjs(self, ifacename):
-        return self.ifaceobjdict.get(ifacename)
-
-    def ifaceobj_sync(self, ifaceobj, op):
-        """This member function sync's new obj state to old statemanager state
-
-        Args:
-            ifaceobj (object): new iface object
-            op (str): ifupdown operation
-        """
-
-        self.logger.debug('%s: statemanager sync state %s'
-                          %(ifaceobj.name, op))
-        old_ifaceobjs = self.ifaceobjdict.get(ifaceobj.name)
-        if 'up' in op:
-            if not old_ifaceobjs:
-                self.ifaceobjdict[ifaceobj.name] = [ifaceobj]
-            else:
-                # If it matches any of the object, return
-                if any(o.compare(ifaceobj) for o in old_ifaceobjs):
-                    return
-                # If it does not match any of the objects, and if
-                # all objs in the list came from the pickled file,
-                # then reset the list and add this object as a fresh one,
-                # else append to the list
-                if old_ifaceobjs[0].flags & iface._PICKLED:
-                    del self.ifaceobjdict[ifaceobj.name]
-                    self.ifaceobjdict[ifaceobj.name] = [ifaceobj]
-                else:
-                    self.ifaceobjdict[ifaceobj.name].append(ifaceobj)
-        elif 'down' in op:
-            # If down of object successfull, delete object from state manager
-            if not old_ifaceobjs:
-                return
-            if ifaceobj.status != ifaceStatus.SUCCESS:
-                return
-            # If it matches any of the object, return
-            oidx = 0
-            for o in old_ifaceobjs:
-                if o.compare(ifaceobj):
-                    old_ifaceobjs.pop(oidx)
-                    if not len(old_ifaceobjs):
-                        del self.ifaceobjdict[ifaceobj.name]
-                    return
-                oidx += 1
-
-    def save_state(self):
-        """ saves state (ifaceobjects) to persistent state file """
-
-        try:
-            with open(self.state_file, 'w') as f:
-                if not len(self.ifaceobjdict):
-                    f.truncate(0)
-                    return
-                self.logger.debug('saving state ..')
-                for ifaceobjs in self.ifaceobjdict.values():
-                    [pickling.save_obj(f, i) for i in ifaceobjs]
-        except:
-            raise
-
-    def dump_pretty(self, ifacenames, format='native'):
-        if not ifacenames:
-            ifacenames = self.ifaceobjdict.keys()
-        for i in ifacenames:
-            ifaceobjs = self.get_ifaceobjs(i)
-            if not ifaceobjs:
-                continue
-            for ifaceobj in ifaceobjs:
-                if format == 'json':
-                    ifaceobj.dump_json()
-                else:
-                    ifaceobj.dump_pretty()
-
-    def dump(self, ifacenames=None):
-        self.logger.debug('statemanager iface state:')
-        if ifacenames:
-            for i in ifacenames:
-                ifaceobj = self.ifaces.get(i)
-                if ifaceobj is None:
-                    raise ifaceNotFoundError('ifname %s'
-                        %i + ' not found')
-                ifaceobj.dump(self.logger)
-        else:
-            for ifacename, ifaceobjs in self.ifaceobjdict.items():
-                [i.dump(self.logger) for i in ifaceobjs]
diff --git a/ifupdown2/ifupdown/template.py b/ifupdown2/ifupdown/template.py
deleted file mode 100644 (file)
index f1792cc..0000000
+++ /dev/null
@@ -1,59 +0,0 @@
-#!/usr/bin/python
-#
-# Copyright 2014 Cumulus Networks, Inc. All rights reserved.
-# Author: Roopa Prabhu, roopa@cumulusnetworks.com
-#
-# template --
-#    helper class to render templates
-#
-
-import logging
-import traceback
-from utils import *
-
-class templateEngine():
-    """ provides template rendering methods """
-
-    def __init__(self, template_engine, template_lookuppath=None):
-        self.logger = logging.getLogger('ifupdown.' +
-                    self.__class__.__name__)
-        self.tclass = None
-        self.tclassargs = {}
-        self.render = self._render_default
-        if template_engine == 'mako':
-            try:
-                self.tclass = utils.importName('mako.template', 'Template')
-            except Exception, e:
-                self.logger.warn('unable to load template engine %s (%s)'
-                        %(template_engine, str(e)))
-                pass
-            if template_lookuppath:
-                try:
-                    self.logger.debug('setting template lookuppath to %s'
-                            %template_lookuppath)
-                    lc = utils.importName('mako.lookup', 'TemplateLookup')
-                    self.tclassargs['lookup'] = lc(
-                                directories=template_lookuppath.split(':'))
-                except Exception, e:
-                    self.logger.warn('unable to set template lookup path' +
-                                ' %s (%s)' %(template_lookuppath, str(e)))
-                    pass
-            self.render = self._render_mako
-        else:
-            self.logger.info('skip template processing.., ' +
-                    'template engine not found')
-
-    def _render_default(self, textdata):
-        return textdata
-
-    def _render_mako(self, textdata):
-        """ render textdata passed as argument using mako
-
-        Returns rendered textdata """
-
-        if not self.tclass:
-            return textdata
-        self.logger.info('template processing on interfaces file ...')
-        t = self.tclass(text=textdata, output_encoding='utf-8',
-                     lookup=self.tclassargs.get('lookup'))
-        return t.render()
diff --git a/ifupdown2/ifupdown/utils.py b/ifupdown2/ifupdown/utils.py
deleted file mode 100644 (file)
index caf6583..0000000
+++ /dev/null
@@ -1,52 +0,0 @@
-#!/usr/bin/python
-#
-# Copyright 2014 Cumulus Networks, Inc. All rights reserved.
-# Author: Roopa Prabhu, roopa@cumulusnetworks.com
-#
-# utils --
-#    helper class
-#
-import os
-import fcntl
-import re
-
-class utils():
-
-    @classmethod
-    def importName(cls, modulename, name):
-        """ Import a named object """
-        try:
-            module = __import__(modulename, globals(), locals(), [name])
-        except ImportError:
-            return None
-        return getattr(module, name)
-
-    @classmethod
-    def lockFile(cls, lockfile):
-        try:
-            fp = os.open(lockfile, os.O_CREAT | os.O_TRUNC | os.O_WRONLY)
-            fcntl.flock(fp, fcntl.LOCK_EX | fcntl.LOCK_NB)
-        except IOError:
-            return False
-        return True
-
-    @classmethod
-    def parse_iface_range(cls, name):
-        range_match = re.match("^([\w\.]+)\[([\d]+)-([\d]+)\]", name)
-        if range_match:
-            range_groups = range_match.groups()
-            if range_groups[1] and range_groups[2]:
-                return (range_groups[0], int(range_groups[1], 10),
-                        int(range_groups[2], 10))
-        return None
-
-    @classmethod
-    def expand_iface_range(cls, name):
-        ifacenames = []
-        iface_range = cls.parse_iface_range(name)
-        if iface_range:
-            for i in range(iface_range[1], iface_range[2]):
-                ifacenames.append('%s-%d' %(iface_range[0], i))
-        return ifacenames
-
-
diff --git a/ifupdown2/ifupdownaddons/__init__.py b/ifupdown2/ifupdownaddons/__init__.py
deleted file mode 100644 (file)
index e69de29..0000000
diff --git a/ifupdown2/ifupdownaddons/bridgeutils.py b/ifupdown2/ifupdownaddons/bridgeutils.py
deleted file mode 100644 (file)
index 73f28b1..0000000
+++ /dev/null
@@ -1,501 +0,0 @@
-#!/usr/bin/python
-#
-# Copyright 2014 Cumulus Networks, Inc. All rights reserved.
-# Author: Roopa Prabhu, roopa@cumulusnetworks.com
-#
-
-from ifupdown.iface import *
-from utilsbase import *
-import os
-import re
-import logging
-from cache import *
-
-class brctl(utilsBase):
-    """ This class contains helper functions to interact with the bridgeutils
-    commands """
-
-    _cache_fill_done = False
-
-    def __init__(self, *args, **kargs):
-        utilsBase.__init__(self, *args, **kargs)
-        if self.CACHE and not brctl._cache_fill_done:
-            self._bridge_fill()
-            brctl._cache_fill_done = True
-
-
-    def _bridge_get_mcattrs_from_sysfs(self, bridgename):
-        mcattrs = {}
-        mcattrmap = {'mclmc': 'multicast_last_member_count',
-                     'mcrouter': 'multicast_router',
-                     'mcsnoop' : 'multicast_snooping',
-                     'mcsqc' : 'multicast_startup_query_count',
-                     'mcqifaddr' : 'multicast_query_use_ifaddr',
-                     'mcquerier' : 'multicast_querier',
-                     'hashel' : 'hash_elasticity',
-                     'hashmax' : 'hash_max',
-                     'mclmi' : 'multicast_last_member_interval',
-                     'mcmi' : 'multicast_membership_interval',
-                     'mcqpi' : 'multicast_querier_interval',
-                     'mcqi' : 'multicast_query_interval',
-                     'mcqri' : 'multicast_query_response_interval',
-                     'mcsqi' : 'multicast_startup_query_interval'}
-
-        mcattrsdivby100 = ['mclmi', 'mcmi', 'mcqpi', 'mcqi', 'mcqri', 'mcsqi']
-
-        for m, s in mcattrmap.items():
-            n = self.read_file_oneline('/sys/class/net/%s/bridge/%s'
-                                    %(bridgename, s))
-            if m in mcattrsdivby100:
-                try:
-                    v = int(n) / 100
-                    mcattrs[m] = str(v)
-                except Exception, e:
-                    self.logger.warn('error getting mc attr %s (%s)'
-                                     %(m, str(e)))
-                    pass
-            else:
-                mcattrs[m] = n
-        return mcattrs
-
-    def _bridge_attrs_fill(self, bridgename):
-        battrs = {}
-        bports = {}
-
-        brout = self.exec_command('/sbin/brctl showstp %s' %bridgename)
-        chunks = re.split(r'\n\n', brout, maxsplit=0, flags=re.MULTILINE)
-
-        try:
-            # Get all bridge attributes
-            broutlines = chunks[0].splitlines()
-            #battrs['pathcost'] = broutlines[3].split('path cost')[1].strip()
-            battrs['maxage'] = broutlines[4].split(
-                                'bridge max age')[1].strip().replace('.00', '')
-            battrs['hello'] = broutlines[5].split(
-                                'bridge hello time')[1].strip().replace('.00',
-                                                                        '')
-            battrs['fd'] = broutlines[6].split(
-                                    'bridge forward delay')[1].strip(
-                                            ).replace('.00', '')
-            battrs.update(self._bridge_get_mcattrs_from_sysfs(bridgename))
-
-            # XXX: comment this out until mc attributes become available
-            # with brctl again
-            #battrs['hashel'] = broutlines[10].split('hash elasticity')[1].split()[0].strip()
-            #battrs['hashmax'] = broutlines[10].split('hash max')[1].strip()
-            #battrs['mclmc'] = broutlines[11].split('mc last member count')[1].split()[0].strip()
-            #battrs['mciqc'] = broutlines[11].split('mc init query count')[1].strip()
-            #battrs['mcrouter'] = broutlines[12].split('mc router')[1].split()[0].strip()
-            ##battrs['mcsnoop'] = broutlines[12].split('mc snooping')[1].strip()
-            #battrs['mclmt'] = broutlines[13].split('mc last member timer')[1].split()[0].strip()
-        except Exception, e:
-            self.logger.warn(str(e))
-            pass
-
-        linkCache.update_attrdict([bridgename, 'linkinfo'], battrs)
-
-        for cidx in range(1, len(chunks)):
-            bpout = chunks[cidx].lstrip('\n')
-            if not bpout or bpout[0] == ' ':
-                continue
-            bplines = bpout.splitlines()
-            pname = bplines[0].split()[0]
-            bportattrs = {}
-            try:
-                bportattrs['pathcost'] = bplines[2].split(
-                                            'path cost')[1].strip()
-                bportattrs['fdelay'] = bplines[4].split(
-                                            'forward delay timer')[1].strip()
-                bportattrs['mcrouter'] = self.read_file_oneline(
-                         '/sys/class/net/%s/brport/multicast_router' %pname)
-                bportattrs['mcfl'] = self.read_file_oneline(
-                         '/sys/class/net/%s/brport/multicast_fast_leave' %pname)
-
-                #bportattrs['mcrouters'] = bplines[6].split('mc router')[1].split()[0].strip()
-                #bportattrs['mc fast leave'] = bplines[6].split('mc fast leave')[1].strip()
-            except Exception, e:
-                self.logger.warn(str(e))
-                pass
-            bports[pname] = bportattrs
-            linkCache.update_attrdict([bridgename, 'linkinfo', 'ports'], bports)
-
-    def _bridge_fill(self, bridgename=None, refresh=False):
-        try:
-            # if cache is already filled, return
-            linkCache.get_attr([bridgename, 'linkinfo', 'fd'])
-            return
-        except:
-            pass
-        if not bridgename:
-            brctlout = self.exec_command('/sbin/brctl show')
-        else:
-            brctlout = self.exec_command('/sbin/brctl show ' + bridgename)
-        if not brctlout:
-            return
-
-        for bline in brctlout.splitlines()[1:]:
-            bitems = bline.split()
-            if len(bitems) < 2:
-                continue
-            try:
-                linkCache.update_attrdict([bitems[0], 'linkinfo'],
-                                      {'stp' : bitems[2]})
-            except KeyError:
-                linkCache.update_attrdict([bitems[0]], 
-                                {'linkinfo' : {'stp' : bitems[2]}})
-            self._bridge_attrs_fill(bitems[0])
-
-    def _cache_get(self, attrlist, refresh=False):
-        try:
-            if self.DRYRUN:
-                return None
-            if self.CACHE:
-                if not self._cache_fill_done: 
-                    self._bridge_fill()
-                    self._cache_fill_done = True
-                    return linkCache.get_attr(attrlist)
-                if not refresh:
-                    return linkCache.get_attr(attrlist)
-            self._bridge_fill(attrlist[0], refresh)
-            return linkCache.get_attr(attrlist)
-        except Exception, e:
-            self.logger.debug('_cache_get(%s) : [%s]'
-                    %(str(attrlist), str(e)))
-            pass
-        return None
-
-    def _cache_check(self, attrlist, value, refresh=False):
-        try:
-            attrvalue = self._cache_get(attrlist, refresh)
-            if attrvalue and attrvalue == value:
-                return True
-        except Exception, e:
-            self.logger.debug('_cache_check(%s) : [%s]'
-                    %(str(attrlist), str(e)))
-            pass
-        return False
-
-    def _cache_update(self, attrlist, value):
-        if self.DRYRUN: return
-        try:
-            linkCache.add_attr(attrlist, value)
-        except:
-            pass
-
-    def _cache_delete(self, attrlist):
-        if self.DRYRUN: return
-        try:
-            linkCache.del_attr(attrlist)
-        except:
-            pass
-
-    def _cache_invalidate(self):
-        if self.DRYRUN: return
-        linkCache.invalidate()
-
-    def create_bridge(self, bridgename):
-        if self.bridge_exists(bridgename):
-            return
-        self.exec_command('/sbin/brctl addbr %s' %bridgename)
-        self._cache_update([bridgename], {})
-
-    def delete_bridge(self, bridgename):
-        if not self.bridge_exists(bridgename):
-            return
-        self.exec_command('/sbin/brctl delbr %s' %bridgename)
-        self._cache_invalidate()
-
-    def add_bridge_port(self, bridgename, bridgeportname):
-        """ Add port to bridge """
-        ports = self._cache_get([bridgename, 'linkinfo', 'ports'])
-        if ports and ports.get(bridgeportname):
-            return
-        self.exec_command('/sbin/brctl addif ' + bridgename + ' ' +
-                          bridgeportname)
-        self._cache_update([bridgename, 'linkinfo', 'ports',
-                            bridgeportname], {})
-
-    def delete_bridge_port(self, bridgename, bridgeportname):
-        """ Delete port from bridge """
-        ports = self._cache_get([bridgename, 'linkinfo', 'ports'])
-        if not ports or not ports.get(bridgeportname):
-            return
-        self.exec_command('/sbin/brctl delif ' + bridgename + ' ' +
-                          bridgeportname)
-        self._cache_delete([bridgename, 'linkinfo', 'ports',
-                           'bridgeportname'])
-
-    def set_bridgeport_attrs(self, bridgename, bridgeportname, attrdict):
-        portattrs = self._cache_get([bridgename, 'linkinfo',
-                                       'ports', bridgeportname])
-        if portattrs == None: portattrs = {}
-        for k, v in attrdict.iteritems():
-            if self.CACHE:
-                curval = portattrs.get(k)
-                if curval and curval == v:
-                    continue
-            self.exec_command('/sbin/brctl set%s %s %s %s'
-                              %(k, bridgename, bridgeportname, v))
-
-    def set_bridgeport_attr(self, bridgename, bridgeportname,
-                            attrname, attrval):
-        if self._cache_check([bridgename, 'linkinfo', 'ports',
-                        bridgeportname, attrname], attrval):
-            return
-        self.exec_command('/sbin/brctl set%s %s %s %s' %(attrname, bridgename,
-                          bridgeportname, attrval))
-
-    def set_bridge_attrs(self, bridgename, attrdict):
-        for k, v in attrdict.iteritems():
-            if not v:
-                continue
-            if self._cache_check([bridgename, 'linkinfo', k], v):
-                continue
-            try:
-                self.exec_command('/sbin/brctl set%s %s %s'
-                                  %(k, bridgename, v))
-            except Exception, e:
-                self.logger.warn('%s: %s' %(bridgename, str(e)))
-                pass
-
-    def set_bridge_attr(self, bridgename, attrname, attrval):
-        if self._cache_check([bridgename, 'linkinfo', attrname], attrval):
-            return
-        self.exec_command('/sbin/brctl set%s %s %s'
-                          %(attrname, bridgename, attrval))
-
-    def get_bridge_attrs(self, bridgename):
-        return self._cache_get([bridgename, 'linkinfo'])
-
-    def get_bridgeport_attrs(self, bridgename, bridgeportname):
-        return self._cache_get([bridgename, 'linkinfo', 'ports',
-                                      bridgeportname])
-
-    def get_bridgeport_attr(self, bridgename, bridgeportname, attrname):
-        return self._cache_get([bridgename, 'linkinfo', 'ports',
-                                      bridgeportname, attrname])
-
-    def set_stp(self, bridge, stp_state):
-        self.exec_command('/sbin/brctl stp ' + bridge + ' ' + stp_state)
-
-    def get_stp(self, bridge):
-        sysfs_stpstate = '/sys/class/net/%s/bridge/stp_state' %bridge
-        if not os.path.exists(sysfs_stpstate):
-            return 'error'
-        stpstate = self.read_file_oneline(sysfs_stpstate)
-        if not stpstate:
-            return 'error'
-        try:
-            if int(stpstate) > 0:
-                return 'yes'
-            elif int(stpstate) == 0:
-                return 'no'
-        except:
-            return 'unknown'
-
-    def conv_value_to_user(self, str):
-        try:
-            ret = int(str) / 100
-        except:
-            return None
-        finally:
-            return '%d' %ret
-
-    def read_value_from_sysfs(self, filename, preprocess_func):
-        value = self.read_file_oneline(filename)
-        if not value:
-            return None
-        return preprocess_func(value)
-
-    def set_ageing(self, bridge, ageing):
-        self.exec_command('/sbin/brctl setageing ' + bridge + ' ' + ageing)
-
-    def get_ageing(self, bridge):
-        return self.read_value_from_sysfs('/sys/class/net/%s/bridge/ageing_time'
-                                     %bridge, self.conv_value_to_user)
-
-    def set_bridgeprio(self, bridge, bridgeprio):
-        self.exec_command('/sbin/brctl setbridgeprio ' + bridge + ' ' +
-                            bridgeprio)
-
-    def get_bridgeprio(self, bridge):
-        return self.read_file_oneline(
-                       '/sys/class/net/%s/bridge/priority' %bridge)
-
-    def set_fd(self, bridge, fd):
-        self.exec_command('/sbin/brctl setfd ' + bridge + ' ' + fd)
-
-    def get_fd(self, bridge):
-        return self.read_value_from_sysfs(
-                            '/sys/class/net/%s/bridge/forward_delay'
-                            %bridge, self.conv_value_to_user)
-
-    def set_gcint(self, bridge, gcint):
-        #cmd = '/sbin/brctl setgcint ' + bridge + ' ' + gcint
-        raise Exception('set_gcint not implemented')
-
-    def set_hello(self, bridge, hello):
-        self.exec_command('/sbin/brctl sethello ' + bridge + ' ' + hello)
-
-    def get_hello(self, bridge):
-        return self.read_value_from_sysfs('/sys/class/net/%s/bridge/hello_time'
-                                          %bridge, self.conv_value_to_user)
-
-    def set_maxage(self, bridge, maxage):
-        self.exec_command('/sbin/brctl setmaxage ' + bridge + ' ' + maxage)
-
-    def get_maxage(self, bridge):
-        return self.read_value_from_sysfs('/sys/class/net/%s/bridge/max_age'
-                                          %bridge, self.conv_value_to_user)
-
-    def set_pathcost(self, bridge, port, pathcost):
-        self.exec_command('/sbin/brctl setpathcost %s' %bridge + ' %s' %port +
-                            ' %s' %pathcost)
-
-    def get_pathcost(self, bridge, port):
-        return self.read_file_oneline('/sys/class/net/%s/brport/path_cost'
-                                        %port)
-
-    def set_portprio(self, bridge, port, prio):
-        self.exec_command('/sbin/brctl setportprio %s' %bridge + ' %s' %port +
-                          ' %s' %prio)
-
-    def get_portprio(self, bridge, port):
-        return self.read_file_oneline('/sys/class/net/%s/brport/priority'
-                                        %port)
-
-    def set_hashmax(self, bridge, hashmax):
-        self.exec_command('/sbin/brctl sethashmax %s' %bridge + ' %s' %hashmax)
-
-    def get_hashmax(self, bridge):
-        return self.read_file_oneline('/sys/class/net/%s/bridge/hash_max'
-                                        %bridge)
-
-    def set_hashel(self, bridge, hashel):
-        self.exec_command('/sbin/brctl sethashel %s' %bridge + ' %s' %hashel)
-
-    def get_hashel(self, bridge):
-        return self.read_file_oneline('/sys/class/net/%s/bridge/hash_elasticity'
-                                        %bridge)
-
-    def set_mclmc(self, bridge, mclmc):
-        self.exec_command('/sbin/brctl setmclmc %s' %bridge + ' %s' %mclmc)
-
-    def get_mclmc(self, bridge):
-        return self.read_file_oneline(
-                    '/sys/class/net/%s/bridge/multicast_last_member_count'
-                    %bridge)
-
-    def set_mcrouter(self, bridge, mcrouter):
-        self.exec_command('/sbin/brctl setmcrouter %s' %bridge +
-                          ' %s' %mcrouter)
-
-    def get_mcrouter(self, bridge):
-        return self.read_file_oneline(
-                    '/sys/class/net/%s/bridge/multicast_router' %bridge)
-
-    def set_mcsnoop(self, bridge, mcsnoop):
-        self.exec_command('/sbin/brctl setmcsnoop %s' %bridge +
-                          ' %s' %mcsnoop)
-
-    def get_mcsnoop(self, bridge):
-        return self.read_file_oneline(
-                    '/sys/class/net/%s/bridge/multicast_snooping' %bridge)
-
-    def set_mcsqc(self, bridge, mcsqc):
-        self.exec_command('/sbin/brctl setmcsqc %s' %bridge +
-                          ' %s' %mcsqc)
-
-    def get_mcsqc(self, bridge):
-        return self.read_file_oneline(
-                    '/sys/class/net/%s/bridge/multicast_startup_query_count'
-                    %bridge)
-
-    def set_mcqifaddr(self, bridge, mcqifaddr):
-        self.exec_command('/sbin/brctl setmcqifaddr %s' %bridge +
-                          ' %s' %mcqifaddr)
-
-    def get_mcqifaddr(self, bridge):
-        return self.read_file_oneline(
-                 '/sys/class/net/%s/bridge/multicast_startup_query_use_ifaddr'
-                 %bridge)
-
-    def set_mcquerier(self, bridge, mcquerier):
-        self.exec_command('/sbin/brctl setmcquerier %s' %bridge +
-                          ' %s' %mcquerier)
-
-    def get_mcquerier(self, bridge):
-        return self.read_file_oneline(
-                 '/sys/class/net/%s/bridge/multicast_querier' %bridge)
-
-    def set_mcqv4src(self, bridge, vlan, mcquerier):
-        if vlan == 0 or vlan > 4095:
-            self.logger.warn('mcqv4src vlan \'%d\' invalid range' %vlan)
-            return
-
-        ip = mcquerier.split('.')
-        if len(ip) != 4:
-            self.logger.warn('mcqv4src \'%s\' invalid IPv4 address' %mcquerier)
-            return
-        for k in ip:
-            if not k.isdigit() or int(k, 10) < 0 or int(k, 10) > 255:
-                self.logger.warn('mcqv4src \'%s\' invalid IPv4 address' %mcquerier)
-                return
-
-        self.exec_command('/sbin/brctl setmcqv4src %s' %bridge +
-                          ' %d %s' %(vlan, mcquerier)) 
-
-    def del_mcqv4src(self, bridge, vlan):
-        self.exec_command('/sbin/brctl delmcqv4src %s %d' %(bridge, vlan))
-
-    def get_mcqv4src(self, bridge, vlan=None):
-        mcqv4src = {}
-        mcqout = self.exec_command('/sbin/brctl showmcqv4src %s' %bridge)
-        if not mcqout: return None
-        mcqlines = mcqout.splitlines()
-        for l in mcqlines[1:]:
-            l=l.strip()
-            k, d, v = l.split('\t')
-            if not k or not v:
-                continue
-            mcqv4src[k] = v
-        if vlan:
-            return mcqv4src.get(vlan)
-        return mcqv4src
-
-    def set_mclmi(self, bridge, mclmi):
-        self.exec_command('/sbin/brctl setmclmi %s' %bridge +
-                          ' %s' %mclmi)
-
-    def get_mclmi(self, bridge):
-        return self.read_file_oneline(
-                 '/sys/class/net/%s/bridge/multicast_last_member_interval'
-                 %bridge)
-
-    def set_mcmi(self, bridge, mcmi):
-        self.exec_command('/sbin/brctl setmcmi %s' %bridge +
-                          ' %s' %mcmi)
-
-    def get_mcmi(self, bridge):
-        return self.read_file_oneline(
-                 '/sys/class/net/%s/bridge/multicast_membership_interval'
-                 %bridge)
-
-    def bridge_exists(self, bridge):
-        return os.path.exists('/sys/class/net/%s/bridge' %bridge)
-
-    def is_bridge_port(self, ifacename):
-        return os.path.exists('/sys/class/net/%s/brport' %ifacename)
-
-    def bridge_port_exists(self, bridge, bridgeportname):
-        try:
-            return os.path.exists('/sys/class/net/%s/brif/%s'
-                                  %(bridge, bridgeportname))
-        except Exception:
-            return False
-   
-    def get_bridge_ports(self, bridgename):
-        try:
-            return os.listdir('/sys/class/net/%s/brif/' %bridgename)
-        except:
-            return []
diff --git a/ifupdown2/ifupdownaddons/cache.py b/ifupdown2/ifupdownaddons/cache.py
deleted file mode 100644 (file)
index 61773b5..0000000
+++ /dev/null
@@ -1,90 +0,0 @@
-#!/usr/bin/python
-#
-# Copyright 2014 Cumulus Networks, Inc. All rights reserved.
-# Author: Roopa Prabhu, roopa@cumulusnetworks.com
-#
-
-import pprint
-from collections import OrderedDict
-
-class linkCache():
-    """ This class contains methods and instance variables to cache
-    link info """
-
-    _shared_state = {}
-
-    """ { <ifacename> : { 'ifindex': <index>,
-                          'mtu': <mtu>,
-                          'state' : <state>',
-                          'flags' : <flags>,
-                          'kind' : <kind: bridge, bond, vlan>,
-                          'linkinfo' : {<attr1> : <attrval1>,
-                                        <attr2> : <attrval2>,
-                                        <ports> : {
-                                                  } """
-    links = {}
-    @classmethod
-    def get_attr(cls, mapList):
-        return reduce(lambda d, k: d[k], mapList, linkCache.links)
-
-    @classmethod
-    def set_attr(cls, mapList, value):
-        cls.get_attr(mapList[:-1])[mapList[-1]] = value
-
-    @classmethod
-    def del_attr(cls, mapList):
-        try:
-            del cls.get_attr(mapList[:-1])[mapList[-1]]
-        except:
-            pass
-
-    @classmethod
-    def update_attrdict(cls, mapList, valuedict):
-        try:
-            cls.get_attr(mapList[:-1])[mapList[-1]].update(valuedict)
-        except:
-            cls.get_attr(mapList[:-1])[mapList[-1]] = valuedict
-            pass
-
-    @classmethod
-    def append_to_attrlist(cls, mapList, value):
-        cls.get_attr(mapList[:-1])[mapList[-1]].append(value)
-
-    @classmethod
-    def remove_from_attrlist(cls, mapList, value):
-        try:
-            cls.get_attr(mapList[:-1])[mapList[-1]].remove(value)
-        except:
-            pass
-
-    @classmethod
-    def check_attr(cls, attrlist, value=None):
-        try:
-            cachedvalue = cls.get_attr(attrlist)
-            if value:
-                if cachedvalue == value:
-                    return True
-                else:
-                    return False
-            elif cachedvalue:
-                return True
-            else:
-                return False
-        except:
-            return False
-
-    @classmethod
-    def invalidate(cls):
-        cls.links = {}
-
-    @classmethod
-    def dump(cls):
-        print 'Dumping link cache'
-        pp = pprint.PrettyPrinter(indent=4)
-        pp.pprint(cls.links)
-
-    @classmethod
-    def dump_link(cls, linkname):
-        print 'Dumping link %s' %linkname
-        pp = pprint.PrettyPrinter(indent=4)
-        pp.pprint(cls.links.get(linkname))
diff --git a/ifupdown2/ifupdownaddons/dhclient.py b/ifupdown2/ifupdownaddons/dhclient.py
deleted file mode 100644 (file)
index 811ff40..0000000
+++ /dev/null
@@ -1,86 +0,0 @@
-#!/usr/bin/python
-#
-# Copyright 2014 Cumulus Networks, Inc. All rights reserved.
-# Author: Roopa Prabhu, roopa@cumulusnetworks.com
-#
-
-from utilsbase import *
-import subprocess
-import os
-
-FNULL = open(os.devnull, 'w')
-
-class dhclient(utilsBase):
-    """ This class contains helper methods to interact with the dhclient
-    utility """
-
-    def _pid_exists(self, pidfilename):
-        if os.path.exists(pidfilename):
-            pid = self.read_file_oneline(pidfilename)
-            if not os.path.exists('/proc/%s' %pid):
-                return False
-        else:
-            return False
-        return True
-
-    def is_running(self, ifacename):
-        return self._pid_exists('/run/dhclient.%s.pid' %ifacename)
-
-    def is_running6(self, ifacename):
-        return self._pid_exists('/run/dhclient6.%s.pid' %ifacename)
-
-    def stop(self, ifacename):
-        if os.path.exists('/sbin/dhclient3'):
-            cmd = ['/sbin/dhclient3', '-x', '-pf',
-                   '/run/dhclient.%s.pid' %ifacename, '-lf',
-                   '/var/lib/dhcp3/dhclient.%s.leases' %ifacename,
-                   '%s' %ifacename]
-        else:
-            cmd = ['/sbin/dhclient', '-x', '-pf',
-                   '/run/dhclient.%s.pid' %ifacename,
-                   '-lf', '/var/lib/dhcp/dhclient.%s.leases' %ifacename,
-                   '%s' %ifacename]
-        self.subprocess_check_call(cmd)
-
-    def start(self, ifacename):
-        if os.path.exists('/sbin/dhclient3'):
-            cmd = ['/sbin/dhclient3', '-pf',
-                   '/run/dhclient.%s.pid' %ifacename,
-                   '-lf', '/var/lib/dhcp3/dhclient.%s.leases' %ifacename,
-                   '%s' %ifacename]
-        else:
-            cmd = ['/sbin/dhclient', '-pf', '/run/dhclient.%s.pid' %ifacename,
-                   '-lf', '/var/lib/dhcp/dhclient.%s.leases' %ifacename,
-                   '%s' %ifacename]
-        self.subprocess_check_call(cmd)
-
-    def release(self, ifacename):
-        if os.path.exists('/sbin/dhclient3'):
-            cmd = ['/sbin/dhclient3', '-r', '-pf',
-                   '/run/dhclient.%s.pid' %ifacename, '-lf',
-                   '/var/lib/dhcp3/dhclient.%s.leases' %ifacename,
-                   '%s' %ifacename]
-        else:
-            cmd = ['/sbin/dhclient', '-r', '-pf',
-                   '/run/dhclient.%s.pid' %ifacename,
-                   '-lf', '/var/lib/dhcp/dhclient.%s.leases' %ifacename,
-                   '%s' %ifacename]
-        self.subprocess_check_call(cmd)
-
-    def start6(self, ifacename):
-        self.subprocess_check_call(['dhclient', '-6', '-pf',
-                '/run/dhclient6.%s.pid' %ifacename, '-lf',
-                '/var/lib/dhcp/dhclient.%s.leases ' %ifacename,
-                '%s' %ifacename])
-
-    def stop6(self, ifacename):
-        self.subprocess_check_call(['dhclient', '-6', '-x', '-pf',
-                '/run/dhclient.%s.pid' %ifacename, '-lf',
-                '/var/lib/dhcp/dhclient.%s.leases ' %ifacename,
-                '%s' %ifacename])
-
-    def release6(self, ifacename):
-        self.subprocess_check_call(['dhclient', '-6', '-r', '-pf',
-                '/run/dhclient6.%s.pid' %ifacename, '-lf',
-                '/var/lib/dhcp/dhclient6.%s.leases' %ifacename,
-                '%s' %ifacename])
diff --git a/ifupdown2/ifupdownaddons/ifenslaveutil.py b/ifupdown2/ifupdownaddons/ifenslaveutil.py
deleted file mode 100644 (file)
index c7e0d42..0000000
+++ /dev/null
@@ -1,421 +0,0 @@
-#!/usr/bin/python
-#
-# Copyright 2014 Cumulus Networks, Inc. All rights reserved.
-# Author: Roopa Prabhu, roopa@cumulusnetworks.com
-#
-
-import os
-import re
-from ifupdown.iface import *
-from utilsbase import *
-from iproute2 import *
-from cache import *
-
-class ifenslaveutil(utilsBase):
-    """ This class contains methods to interact with linux kernel bond
-    related interfaces """
-
-    _cache_fill_done = False
-
-    def __init__(self, *args, **kargs):
-        utilsBase.__init__(self, *args, **kargs)
-        if self.CACHE and not self._cache_fill_done:
-            self._bond_linkinfo_fill_all()
-            self._cache_fill_done = True
-
-    def _bond_linkinfo_fill_attrs(self, bondname):
-        try:
-            linkCache.links[bondname]['linkinfo'] = {}
-        except:
-            linkCache.links[bondname] = {'linkinfo': {}}
-
-        try:
-            linkCache.set_attr([bondname, 'linkinfo', 'slaves'],
-                self.read_file_oneline('/sys/class/net/%s/bonding/slaves'
-                %bondname).split())
-            linkCache.set_attr([bondname, 'linkinfo', 'mode'],
-                self.read_file_oneline('/sys/class/net/%s/bonding/mode'
-                %bondname).split()[0])
-            linkCache.set_attr([bondname, 'linkinfo', 'xmit_hash_policy'],
-                self.read_file_oneline(
-                    '/sys/class/net/%s/bonding/xmit_hash_policy'
-                    %bondname).split()[0])
-            linkCache.set_attr([bondname, 'linkinfo', 'lacp_rate'],
-                self.read_file_oneline('/sys/class/net/%s/bonding/lacp_rate'
-                                       %bondname).split()[1])
-            linkCache.set_attr([bondname, 'linkinfo', 'ad_sys_priority'],
-                self.read_file_oneline('/sys/class/net/%s/bonding/ad_sys_priority'
-                                       %bondname))
-            linkCache.set_attr([bondname, 'linkinfo', 'ad_sys_mac_addr'],
-                self.read_file_oneline('/sys/class/net/%s/bonding/ad_sys_mac_addr'
-                                       %bondname))
-            map(lambda x: linkCache.set_attr([bondname, 'linkinfo', x],
-                   self.read_file_oneline('/sys/class/net/%s/bonding/%s'
-                        %(bondname, x))),
-                       ['use_carrier', 'miimon', 'min_links', 'num_unsol_na',
-                        'num_grat_arp', 'lacp_bypass_allow', 'lacp_bypass_period', 
-                        'clag_enable'])
-        except Exception, e:
-            pass
-
-    def _bond_linkinfo_fill_all(self):
-        bondstr = self.read_file_oneline('/sys/class/net/bonding_masters')
-        if not bondstr:
-            return
-        [self._bond_linkinfo_fill_attrs(b) for b in bondstr.split()]
-
-    def _bond_linkinfo_fill(self, bondname, refresh=False):
-        try:
-            linkCache.get_attr([bondname, 'linkinfo', 'slaves'])
-            return
-        except:
-            pass
-        bondstr = self.read_file_oneline('/sys/class/net/bonding_masters')
-        if (not bondstr or bondname not in bondstr.split()):
-            raise Exception('bond %s not found' %bondname)
-        self._bond_linkinfo_fill_attrs(bondname)
-
-    def _cache_get(self, attrlist, refresh=False):
-        try:
-            if self.DRYRUN:
-                return None
-            if self.CACHE:
-                if not ifenslaveutil._cache_fill_done: 
-                    self._bond_linkinfo_fill_all()
-                    ifenslaveutil._cache_fill_done = True
-                    return linkCache.get_attr(attrlist)
-                if not refresh:
-                    return linkCache.get_attr(attrlist)
-            self._bond_linkinfo_fill(attrlist[0], refresh)
-            return linkCache.get_attr(attrlist)
-        except Exception, e:
-            self.logger.debug('_cache_get(%s) : [%s]'
-                    %(str(attrlist), str(e)))
-            pass
-        return None
-
-    def _cache_check(self, attrlist, value, refresh=False):
-        try:
-            attrvalue = self._cache_get(attrlist, refresh)
-            if attrvalue and attrvalue == value:
-                return True
-        except Exception, e:
-            self.logger.debug('_cache_check(%s) : [%s]'
-                    %(str(attrlist), str(e)))
-            pass
-        return False
-
-    def _cache_update(self, attrlist, value):
-        if self.DRYRUN: return
-        try:
-            if attrlist[-1] == 'slaves':
-                linkCache.add_to_attrlist(attrlist, value)
-                return
-            linkCache.add_attr(attrlist, value)
-        except:
-            pass
-
-    def _cache_delete(self, attrlist, value=None):
-        if self.DRYRUN: return
-        try:
-            if attrlist[-1] == 'slaves':
-                linkCache.remove_from_attrlist(attrlist, value)
-                return
-            linkCache.del_attr(attrlist)
-        except:
-            pass
-
-    def _cache_invalidate(self):
-        if self.DRYRUN: return
-        linkCache.invalidate()
-
-    def set_attrs(self, bondname, attrdict, prehook):
-        for attrname, attrval in attrdict.items():
-            if (self._cache_check([bondname, 'linkinfo',
-                attrname], attrval)):
-                continue
-            if (attrname == 'mode' or attrname == 'xmit_hash_policy' or
-                    attrname == 'lacp_rate' or attrname == 'min_links'):
-                if prehook:
-                    prehook(bondname)
-            try:
-                self.write_file('/sys/class/net/%s/bonding/%s'
-                                %(bondname, attrname), attrval)
-            except Exception, e:
-                if self.FORCE:
-                    self.logger.warn(str(e))
-                    pass
-                else:
-                    raise
-
-    def set_use_carrier(self, bondname, use_carrier):
-        if not use_carrier or (use_carrier != '0' and use_carrier != '1'):
-            return
-        if (self._cache_check([bondname, 'linkinfo', 'use_carrier'],
-                use_carrier)):
-                return
-        self.write_file('/sys/class/net/%s' %bondname +
-                         '/bonding/use_carrier', use_carrier)
-        self._cache_update([bondname, 'linkinfo',
-                            'use_carrier'], use_carrier)
-
-    def get_use_carrier(self, bondname):
-        return self._cache_get([bondname, 'linkinfo', 'use_carrier'])
-
-    def set_xmit_hash_policy(self, bondname, hash_policy, prehook=None):
-        valid_values = ['layer2', 'layer3+4', 'layer2+3']
-        if not hash_policy:
-            return
-        if hash_policy not in valid_values:
-            raise Exception('invalid hash policy value %s' %hash_policy)
-        if (self._cache_check([bondname, 'linkinfo', 'xmit_hash_policy'],
-                hash_policy)):
-            return
-        if prehook:
-            prehook(bondname)
-        self.write_file('/sys/class/net/%s' %bondname +
-                         '/bonding/xmit_hash_policy', hash_policy)
-        self._cache_update([bondname, 'linkinfo', 'xmit_hash_policy'],
-                hash_policy)
-
-    def get_xmit_hash_policy(self, bondname):
-        return self._cache_get([bondname, 'linkinfo', 'xmit_hash_policy'])
-
-    def set_miimon(self, bondname, miimon):
-        if (self._cache_check([bondname, 'linkinfo', 'miimon'],
-                miimon)):
-            return
-        self.write_file('/sys/class/net/%s' %bondname +
-                '/bonding/miimon', miimon)
-        self._cache_update([bondname, 'linkinfo', 'miimon'], miimon)
-
-    def get_miimon(self, bondname):
-        return self._cache_get([bondname, 'linkinfo', 'miimon'])
-
-    def set_clag_enable(self, bondname, clag_id):
-        clag_enable = '0' if clag_id == '0' else '1'
-        if self._cache_check([bondname, 'linkinfo', 'clag_enable'], 
-                        clag_enable) == False:
-            self.write_file('/sys/class/net/%s' %bondname +
-                        '/bonding/clag_enable', clag_enable)
-            self._cache_update([bondname, 'linkinfo', 'clag_enable'], 
-                        clag_enable)
-
-    def get_clag_enable(self, bondname):
-        return self._cache_get([bondname, 'linkinfo', 'clag_enable'])
-
-    def set_mode(self, bondname, mode, prehook=None):
-        valid_modes = ['balance-rr', 'active-backup', 'balance-xor',
-                       'broadcast', '802.3ad', 'balance-tlb', 'balance-alb']
-        if not mode:
-            return
-        if mode not in valid_modes:
-            raise Exception('invalid mode %s' %mode)
-        if (self._cache_check([bondname, 'linkinfo', 'mode'],
-                mode)):
-            return
-        if prehook:
-            prehook(bondname)
-        self.write_file('/sys/class/net/%s' %bondname + '/bonding/mode', mode)
-        self._cache_update([bondname, 'linkinfo', 'mode'], mode)
-
-    def get_mode(self, bondname):
-        return self._cache_get([bondname, 'linkinfo', 'mode'])
-
-    def set_lacp_rate(self, bondname, lacp_rate, prehook=None, posthook=None):
-        if not lacp_rate or (lacp_rate != '0' and lacp_rate != '1'):
-            return
-        if (self._cache_check([bondname, 'linkinfo', 'lacp_rate'],
-                lacp_rate)):
-            return
-        if prehook:
-            prehook(bondname)
-        try:
-            self.write_file('/sys/class/net/%s' %bondname +
-                            '/bonding/lacp_rate', lacp_rate)
-        except:
-            raise
-        finally:
-            if posthook:
-                prehook(bondname)
-            self._cache_update([bondname, 'linkinfo',
-                                'lacp_rate'], lacp_rate)
-
-    def get_lacp_rate(self, bondname):
-        return self._cache_get([bondname, 'linkinfo', 'lacp_rate'])
-
-    def set_lacp_fallback_allow(self, bondname, allow, prehook=None, posthook=None):
-        if (self._cache_check([bondname, 'linkinfo', 'lacp_bypass_allow'],
-                lacp_bypass_allow)):
-            return
-        if prehook:
-            prehook(bondname)
-        try:
-            self.write_file('/sys/class/net/%s' %bondname +
-                            '/bonding/lacp_bypass_allow', allow)
-        except:
-            raise
-        finally:
-            if posthook:
-                posthook(bondname)
-            self._cache_update([bondname, 'linkinfo',
-                               'lacp_bypass_allow'], allow)
-
-    def get_lacp_fallback_allow(self, bondname):
-        return self._cache_get([bondname, 'linkinfo', 'lacp_bypass_allow'])
-
-    def set_lacp_fallback_period(self, bondname, period, prehook=None, posthook=None):
-        if (self._cache_check([bondname, 'linkinfo', 'lacp_bypass_period'],
-                lacp_bypass_period)):
-            return
-        if prehook:
-            prehook(bondname)
-        try:
-            self.write_file('/sys/class/net/%s' %bondname + 
-                            '/bonding/lacp_bypass_period', period)
-        except:
-            raise
-        finally:
-            if posthook:
-                posthook(bondname)
-            self._cache_update([bondname, 'linkinfo',
-                               'lacp_bypass_period'], period)
-
-    def get_lacp_fallback_period(self, bondname):
-        return self._cache_get([bondname, 'linkinfo', 'lacp_bypass_period']) 
-
-    def set_min_links(self, bondname, min_links, prehook=None):
-        if (self._cache_check([bondname, 'linkinfo', 'min_links'],
-                min_links)):
-            return
-        if prehook:
-            prehook(bondname)
-        self.write_file('/sys/class/net/%s/bonding/min_links' %bondname,
-                         min_links)
-        self._cache_update([bondname, 'linkinfo', 'min_links'], min_links)
-
-    def get_min_links(self, bondname):
-        return self._cache_get([bondname, 'linkinfo', 'min_links'])
-
-    def set_lacp_fallback_priority(self, bondname, port, val):
-        slavefile = '/sys/class/net/%s/bonding_slave/lacp_bypass_priority' %port
-        if os.path.exists(slavefile):
-            self.write_file(slavefile, val)
-
-    def get_lacp_fallback_priority(self, bondname):
-        slaves = self.get_slaves(bondname)
-        if not slaves:
-            return slaves
-        prios = []
-        for slave in slaves:
-            priofile = '/sys/class/net/%s/bonding_slave/lacp_bypass_priority' %slave
-            if os.path.exists(priofile):
-                val = self.read_file_oneline(priofile)
-                if val and val != '0':
-                    prio = slave + '=' + val
-                    prios.append(prio)
-        prios.sort()
-        prio_str = ' '.join(prios)
-        return prio_str
-
-    def get_ad_sys_mac_addr(self, bondname):
-        return self._cache_get([bondname, 'linkinfo', 'ad_sys_mac_addr'])
-
-    def get_ad_sys_priority(self, bondname):
-        return self._cache_get([bondname, 'linkinfo', 'ad_sys_priority'])
-
-    def enslave_slave(self, bondname, slave, prehook=None, posthook=None):
-        slaves = self._cache_get([bondname, 'linkinfo', 'slaves'])
-        if slaves and slave in slaves: return
-        if prehook:
-            prehook(slave)
-        self.write_file('/sys/class/net/%s' %bondname +
-                         '/bonding/slaves', '+' + slave)
-        if posthook:
-            posthook(slave)
-        self._cache_update([bondname, 'linkinfo', 'slaves'], slave) 
-
-    def remove_slave(self, bondname, slave):
-        slaves = self._cache_get([bondname, 'linkinfo', 'slaves'])
-        if slave not in slaves:
-            return
-        sysfs_bond_path = ('/sys/class/net/%s' %bondname +
-                           '/bonding/slaves')
-        if not os.path.exists(sysfs_bond_path):
-           return
-        self.write_file(sysfs_bond_path, '-' + slave)
-        self._cache_delete([bondname, 'linkinfo', 'slaves'], slave) 
-
-    def remove_slaves_all(self, bondname):
-        if not _self._cache_get([bondname, 'linkinfo', 'slaves']):
-            return
-        slaves = None
-        sysfs_bond_path = ('/sys/class/net/%s' %bondname +
-                           '/bonding/slaves')
-        ipcmd = iproute2()
-        try:
-            f = open(sysfs_bond_path, 'r')
-            slaves = f.readline().strip().split()
-            f.close()
-        except IOError, e:
-            raise Exception('error reading slaves of bond %s' %bondname
-                + '(' + str(e) + ')')
-        for slave in slaves:
-            ipcmd.ip_link_down(slave)
-            try:
-                self.remove_slave(bondname, slave)
-            except Exception, e:
-                if not self.FORCE:
-                    raise Exception('error removing slave %s'
-                        %slave + ' from bond %s' %bondname +
-                        '(%s)' %str(e))
-                else:
-                    pass
-        self._cache_del([bondname, 'linkinfo', 'slaves'])
-
-    def load_bonding_module(self):
-        return self.exec_command('modprobe -q bonding')
-
-    def create_bond(self, bondname):
-        if self.bond_exists(bondname):
-            return
-        sysfs_net = '/sys/class/net/'
-        sysfs_bonding_masters = sysfs_net + 'bonding_masters'
-        if not os.path.exists(sysfs_bonding_masters):
-            self.logger.debug('loading bonding driver')
-            self.load_bonding_module()
-            return True
-        self.write_file(sysfs_bonding_masters, '+' + bondname)
-        self._cache_update([bondname], {})
-
-    def delete_bond(self, bondname):
-        if not os.path.exists('/sys/class/net/%s' %bondname):
-            return
-        self.write_file('/sys/class/net/bonding_masters', '-' + bondname)
-        self._cache_delete([bondname])
-
-    def unset_master(self, bondname):
-        print 'Do nothing yet'
-        return 0
-
-    def get_slaves(self, bondname):
-        slaves = self._cache_get([bondname, 'linkinfo', 'slaves'])
-        if slaves:
-            return list(slaves)
-        slavefile = '/sys/class/net/%s/bonding/slaves' %bondname
-        if os.path.exists(slavefile):
-            buf = self.read_file_oneline(slavefile)
-            if buf:
-                slaves = buf.split()
-        if not slaves:
-            return slaves
-        self._cache_update([bondname, 'linkinfo', 'slaves'], slaves)
-        return list(slaves)
-
-    def bond_slave_exists(self, bond, slave):
-        slaves = self.get_slaves(bond)
-        if not slaves: return False
-        return slave in slaves
-
-    def bond_exists(self, bondname):
-        return os.path.exists('/sys/class/net/%s/bonding' %bondname)
diff --git a/ifupdown2/ifupdownaddons/iproute2.py b/ifupdown2/ifupdownaddons/iproute2.py
deleted file mode 100644 (file)
index c56df83..0000000
+++ /dev/null
@@ -1,777 +0,0 @@
-#!/usr/bin/python
-#
-# Copyright 2014 Cumulus Networks, Inc. All rights reserved.
-# Author: Roopa Prabhu, roopa@cumulusnetworks.com
-#
-
-import os
-from collections import OrderedDict
-from utilsbase import *
-from cache import *
-
-VXLAN_UDP_PORT = 4789
-
-class iproute2(utilsBase):
-    """ This class contains helper methods to cache and interact with the
-    commands in the iproute2 package """
-
-    _cache_fill_done = False
-    ipbatchbuf = ''
-    ipbatch = False
-    ipbatch_pause = False
-
-    def __init__(self, *args, **kargs):
-        utilsBase.__init__(self, *args, **kargs)
-        if self.CACHE and not iproute2._cache_fill_done:
-            self._link_fill()
-            self._addr_fill()
-            iproute2._cache_fill_done = True
-        
-    def _link_fill(self, ifacename=None, refresh=False):
-        """ fills cache with link information
-       
-        if ifacename argument given, fill cache for ifacename, else
-        fill cache for all interfaces in the system
-        """
-
-        linkout = {}
-        if iproute2._cache_fill_done and not refresh: return
-        try:
-            # if ifacename already present, return
-            if (ifacename and not refresh and
-                    linkCache.get_attr([ifacename, 'ifflag'])):
-                return
-        except:
-            pass
-        cmdout = self.link_show(ifacename=ifacename)
-        if not cmdout:
-            return
-        for c in cmdout.splitlines():
-            citems = c.split()
-            ifnamenlink = citems[1].split('@')
-            if len(ifnamenlink) > 1:
-                ifname = ifnamenlink[0]
-                iflink = ifnamenlink[1].strip(':')
-            else:
-                ifname = ifnamenlink[0].strip(':')
-                iflink = None
-            linkattrs = {}
-            linkattrs['link'] = iflink
-            linkattrs['ifindex'] = citems[0].strip(':')
-            flags = citems[2].strip('<>').split(',')
-            linkattrs['flags'] = flags
-            linkattrs['ifflag'] = 'UP' if 'UP' in flags else 'DOWN'
-            for i in range(0, len(citems)):
-                if citems[i] == 'mtu': linkattrs['mtu'] = citems[i+1]
-                elif citems[i] == 'state': linkattrs['state'] = citems[i+1]
-                elif citems[i] == 'link/ether': linkattrs['hwaddress'] = citems[i+1]
-                elif citems[i] == 'vlan' and citems[i+1] == 'id':
-                    linkattrs['linkinfo'] = {'vlanid' : citems[i+2]}
-                elif citems[i] == 'vxlan' and citems[i+1] == 'id':
-                    vattrs = {'vxlanid' : citems[i+2],
-                              'svcnode' : [],
-                              'remote'  : [],
-                              'ageing' : citems[i+2],
-                              'learning': 'on'}
-                    for j in range(i+2, len(citems)):
-                        if citems[j] == 'local':
-                            vattrs['local'] = citems[j+1]
-                        elif citems[j] == 'svcnode':
-                            vattrs['svcnode'].append(citems[j+1])
-                        elif citems[j] == 'peernode':
-                            vattrs['peernode'].append(citems[j+1])
-                        elif citems[j] == 'nolearning':
-                            vattrs['learning'] = 'off'
-                    # get vxlan peer nodes
-                    peers = self.get_vxlan_peers(ifname)
-                    if peers:
-                        vattrs['remote'] = peers
-                    linkattrs['linkinfo'] = vattrs
-                    break
-            #linkattrs['alias'] = self.read_file_oneline(
-            #            '/sys/class/net/%s/ifalias' %ifname)
-            linkout[ifname] = linkattrs
-        [linkCache.update_attrdict([ifname], linkattrs)
-                    for ifname, linkattrs in linkout.items()]
-
-    def _addr_filter(self, addr, scope=None):
-        default_addrs = ['127.0.0.1/8', '::1/128' , '0.0.0.0']
-        if addr in default_addrs:
-            return True
-        if scope and scope == 'link':
-            return True
-        return False
-
-    def _addr_fill(self, ifacename=None, refresh=False):
-        """ fills cache with address information
-       
-        if ifacename argument given, fill cache for ifacename, else
-        fill cache for all interfaces in the system
-        """
-
-        linkout = {}
-        if iproute2._cache_fill_done: return
-        try:
-            # Check if ifacename is already full, in which case, return
-            if ifacename:
-                linkCache.get_attr([ifacename, 'addrs']) 
-                return
-        except:
-            pass
-        cmdout = self.addr_show(ifacename=ifacename)
-        if not cmdout:
-            return
-        for c in cmdout.splitlines():
-            citems = c.split()
-            ifnamenlink = citems[1].split('@')
-            if len(ifnamenlink) > 1:
-                ifname = ifnamenlink[0]
-            else:
-                ifname = ifnamenlink[0].strip(':')
-            if citems[2] == 'inet':
-                if self._addr_filter(citems[3], scope=citems[5]):
-                    continue
-                addrattrs = {}
-                addrattrs['scope'] = citems[5]
-                addrattrs['type'] = 'inet'
-                linkout[ifname]['addrs'][citems[3]] = addrattrs
-            elif citems[2] == 'inet6':
-                if self._addr_filter(citems[3], scope=citems[5]):
-                    continue
-                if citems[5] == 'link': continue #skip 'link' addresses
-                addrattrs = {}
-                addrattrs['scope'] = citems[5]
-                addrattrs['type'] = 'inet6'
-                linkout[ifname]['addrs'][citems[3]] = addrattrs
-            else:
-                linkattrs = {}
-                linkattrs['addrs'] = OrderedDict({})
-                try:
-                    linkout[ifname].update(linkattrs)
-                except KeyError:
-                    linkout[ifname] = linkattrs
-
-        [linkCache.update_attrdict([ifname], linkattrs)
-                    for ifname, linkattrs in linkout.items()]
-
-    def _cache_get(self, type, attrlist, refresh=False):
-        try:
-            if self.DRYRUN:
-                return False
-            if self.CACHE:
-                if not iproute2._cache_fill_done: 
-                    self._link_fill()
-                    self._addr_fill()
-                    iproute2._cache_fill_done = True
-                    return linkCache.get_attr(attrlist)
-                if not refresh:
-                    return linkCache.get_attr(attrlist)
-            if type == 'link':
-                self._link_fill(attrlist[0], refresh)
-            elif type == 'addr':
-                self._addr_fill(attrlist[0], refresh)
-            else:
-                self._link_fill(attrlist[0], refresh)
-                self._addr_fill(attrlist[0], refresh)
-            return linkCache.get_attr(attrlist)
-        except Exception, e:
-            self.logger.debug('_cache_get(%s) : [%s]'
-                    %(str(attrlist), str(e)))
-            pass
-        return None
-
-    def _cache_check(self, type, attrlist, value, refresh=False):
-        try:
-            attrvalue = self._cache_get(type, attrlist, refresh)
-            if attrvalue and attrvalue == value:
-                return True
-        except Exception, e:
-            self.logger.debug('_cache_check(%s) : [%s]'
-                    %(str(attrlist), str(e)))
-            pass
-        return False
-
-    def _cache_update(self, attrlist, value):
-        if self.DRYRUN: return
-        try:
-            linkCache.add_attr(attrlist, value)
-        except:
-            pass
-
-    def _cache_delete(self, attrlist):
-        if self.DRYRUN: return
-        try:
-            linkCache.del_attr(attrlist)
-        except:
-            pass
-
-    def _cache_invalidate(self):
-        linkCache.invalidate()
-
-    def batch_start(self):
-        self.ipbatcbuf = ''
-        self.ipbatch = True
-        self.ipbatch_pause = False
-
-    def add_to_batch(self, cmd):
-        self.ipbatchbuf += cmd + '\n'
-
-    def batch_pause(self):
-        self.ipbatch_pause = True
-
-    def batch_resume(self):
-        self.ipbatch_pause = False
-
-    def batch_commit(self):
-        if not self.ipbatchbuf:
-            return
-        try:
-            self.exec_command_talk_stdin('ip -force -batch -',
-                    stdinbuf=self.ipbatchbuf)
-        except Exception:
-            raise
-        finally:
-            self.ipbatchbuf = ''
-            self.ipbatch = False
-            self.ipbatch_pause = False
-
-    def addr_show(self, ifacename=None):
-        if ifacename:
-            if not self.link_exists(ifacename):
-                return
-            return self.exec_commandl(['ip','-o', 'addr', 'show', 'dev',
-                    '%s' %ifacename])
-        else:
-            return self.exec_commandl(['ip', '-o', 'addr', 'show'])
-
-    def link_show(self, ifacename=None):
-        if ifacename:
-            return self.exec_commandl(['ip', '-o', '-d', 'link',
-                    'show', 'dev', '%s' %ifacename])
-        else:
-            return self.exec_commandl(['ip', '-o', '-d', 'link', 'show'])
-
-    def addr_add(self, ifacename, address, broadcast=None,
-                    peer=None, scope=None, preferred_lifetime=None):
-        if not address:
-            return
-        cmd = 'addr add %s' %address
-        if broadcast:
-            cmd += ' broadcast %s' %broadcast
-        if peer:
-            cmd += ' peer %s' %peer
-        if scope:
-            cmd += ' scope %s' %scope
-        if preferred_lifetime:
-            cmd += ' preferred_lft %s' %preferred_lifetime
-        cmd += ' dev %s' %ifacename
-        if self.ipbatch and not self.ipbatch_pause:
-            self.add_to_batch(cmd)
-        else:
-            self.exec_command('ip ' + cmd)
-        self._cache_update([ifacename, 'addrs', address], {})
-
-    def addr_del(self, ifacename, address, broadcast=None,
-                    peer=None, scope=None):
-        """ Delete ipv4 address """
-        if not address:
-            return
-        if not self._cache_get('addr', [ifacename, 'addrs', address]):
-            return
-        cmd = 'addr del %s' %address
-        if broadcast:
-            cmd += 'broadcast %s' %broadcast
-        if peer:
-            cmd += 'peer %s' %peer
-        if scope:
-            cmd += 'scope %s' %scope
-        cmd += ' dev %s' %ifacename
-        self.exec_command('ip ' + cmd)
-        self._cache_delete([ifacename, 'addrs', address])
-
-    def addr_flush(self, ifacename):
-        cmd = 'addr flush dev %s' %ifacename
-        if self.ipbatch and not self.ipbatch_pause:
-            self.add_to_batch(cmd)
-        else:
-            self.exec_command('ip ' + cmd)
-        self._cache_delete([ifacename, 'addrs'])
-
-    def del_addr_all(self, ifacename, skip_addrs=[]):
-        if not skip_addrs: skip_addrs = []
-        runningaddrsdict = self.addr_get(ifacename)
-        try:
-            # XXX: ignore errors. Fix this to delete secondary addresses
-            # first
-            [self.addr_del(ifacename, a) for a in
-                set(runningaddrsdict.keys()).difference(skip_addrs)]
-        except:
-            # ignore errors
-            pass
-
-    def addr_get(self, ifacename, details=True):
-        addrs = self._cache_get('addr', [ifacename, 'addrs'])
-        if not addrs:
-            return None
-        if details:
-            return addrs
-        return addrs.keys()
-
-    def addr_add_multiple(self, ifacename, addrs, purge_existing=False):
-        # purges address
-        if purge_existing:
-            # if perfmode is not set and also if iface has no sibling
-            # objects, purge addresses that are not present in the new
-            # config
-            runningaddrs = self.addr_get(ifacename, details=False)
-            if addrs == runningaddrs:
-                return
-            try:
-                # if primary address is not same, there is no need to keep any.
-                # reset all addresses
-                if (addrs and runningaddrs and
-                        (addrs[0] != runningaddrs[0])):
-                    self.del_addr_all(ifacename)
-                else:
-                    self.del_addr_all(ifacename, addrs)
-            except Exception, e:
-                self.log_warn(str(e))
-        for a in addrs:
-            try:
-                self.addr_add(ifacename, a)
-            except Exception, e:
-                self.logger.error(str(e))
-
-    def _link_set_ifflag(self, ifacename, value):
-        # Dont look at the cache, the cache may have stale value
-        # because link status can be changed by external
-        # entity (One such entity is ifupdown main program)
-        cmd = 'link set dev %s %s' %(ifacename, value.lower())
-        if self.ipbatch:
-            self.add_to_batch(cmd)
-        else:
-            self.exec_command('ip ' + cmd)
-
-    def link_up(self, ifacename):
-        self._link_set_ifflag(ifacename, 'UP')
-
-    def link_down(self, ifacename):
-        self._link_set_ifflag(ifacename, 'DOWN')
-
-    def link_set(self, ifacename, key, value=None, force=False):
-        if not force:
-            if (key not in ['master', 'nomaster'] and
-                self._cache_check('link', [ifacename, key], value)):
-                return
-        cmd = 'link set dev %s %s' %(ifacename, key)
-        if value:
-            cmd += ' %s' %value
-        if self.ipbatch:
-            self.add_to_batch(cmd)
-        else:
-            self.exec_command('ip ' + cmd)
-        if key not in ['master', 'nomaster']:
-            self._cache_update([ifacename, key], value)
-
-    def link_set_hwaddress(self, ifacename, hwaddress, force=False):
-        if not force:
-            if self._cache_check('link', [ifacename, 'hwaddress'], hwaddress):
-               return
-        self.link_down(ifacename)
-        cmd = 'link set dev %s address %s' %(ifacename, hwaddress)
-        if self.ipbatch:
-            self.add_to_batch(cmd)
-        else:
-            self.exec_command('ip ' + cmd)
-        self.link_up(ifacename)
-        self._cache_update([ifacename, 'hwaddress'], hwaddress)
-
-    def link_set_alias(self, ifacename, alias):
-        self.exec_commandl(['ip', 'link', 'set', 'dev',
-                    ifacename, 'alias', alias])
-
-    def link_get_alias(self, ifacename):
-        return self.read_file_oneline('/sys/class/net/%s/ifalias'
-                    %ifacename)
-
-    def link_isloopback(self, ifacename):
-        flags = self._cache_get('link', [ifacename, 'flags'])
-        if not flags:
-            return
-        if 'LOOPBACK' in flags:
-            return True
-        return False
-
-    def link_get_status(self, ifacename):
-        return self._cache_get('link', [ifacename, 'ifflag'], refresh=True)
-
-    def route_add_gateway(self, ifacename, gateway, metric=None):
-        if not gateway:
-           return
-        cmd = 'ip route add default via %s' %gateway
-        # Add metric
-        if metric:
-            cmd += 'metric %s' %metric
-        cmd += ' dev %s' %ifacename
-        self.exec_command(cmd)
-
-    def route_del_gateway(self, ifacename, gateway, metric=None):
-        # delete default gw
-        if not gateway:
-            return
-        cmd = 'ip route del default via %s' %gateway
-        if metric:
-            cmd += ' metric %s' %metric
-        cmd += ' dev %s' %ifacename
-        self.exec_command(cmd)
-
-    def route6_add_gateway(self, ifacename, gateway):
-        if not gateway:
-            return
-        return self.exec_command('ip -6 route add default via %s' %gateway +
-                                 ' dev %s' %ifacename)
-
-    def route6_del_gateway(self, ifacename, gateway):
-        if not gateway:
-            return
-        return self.exec_command('ip -6 route del default via %s' %gateway +
-                                 'dev %s' %ifacename)
-
-    def link_create_vlan(self, vlan_device_name, vlan_raw_device, vlanid):
-        if self.link_exists(vlan_device_name):
-            return
-        self.exec_command('ip link add link %s' %vlan_raw_device +
-                          ' name %s' %vlan_device_name +
-                          ' type vlan id %d' %vlanid)
-        self._cache_update([vlan_device_name], {})
-
-    def link_create_vlan_from_name(self, vlan_device_name):
-        v = vlan_device_name.split('.')
-        if len(v) != 2:
-            self.logger.warn('invalid vlan device name %s' %vlan_device_name)
-            return 
-        self.link_create_vlan(vlan_device_name, v[0], v[1])
-
-    def link_create_macvlan(self, name, linkdev, mode='private'):
-        if self.link_exists(name):
-            return
-        cmd = ('link add link %s' %linkdev +
-                          ' name %s' %name +
-                          ' type macvlan mode %s' %mode)
-        if self.ipbatch and not self.ipbatch_pause:
-            self.add_to_batch(cmd)
-        else:
-            self.exec_command('ip %s' %cmd)
-        self._cache_update([name], {})
-
-    def get_vxlan_peers(self, dev):
-        cmd = 'bridge fdb show brport %s' % dev
-        cur_peers = []
-        try:
-            ps = subprocess.Popen((cmd).split(), stdout=subprocess.PIPE, close_fds=True)
-            output = subprocess.check_output(('grep', '00:00:00:00:00:00'), stdin=ps.stdout)
-            ps.wait()
-            try:
-                ppat = re.compile('\s+dst\s+(\d+.\d+.\d+.\d+)\s+')
-                for l in output.split('\n'):
-                    m = ppat.search(l)
-                    if m:
-                        cur_peers.append(m.group(1))
-            except:
-                self.logger.warn('error parsing ip link output')
-                pass
-        except subprocess.CalledProcessError as e:
-            if e.returncode != 1:
-                self.logger.error(str(e))
-
-        return cur_peers
-
-    def link_create_vxlan(self, name, vxlanid,
-                          localtunnelip=None,
-                          svcnodeips=None,
-                          remoteips=None,
-                          learning='on',
-                          ageing=None):
-        if svcnodeips and remoteips:
-            raise Exception("svcnodeip and remoteip is mutually exclusive")
-        args = ''
-        if localtunnelip:
-            args += ' local %s' %localtunnelip
-        if svcnodeips:
-            for s in svcnodeips:
-                args += ' svcnode %s' %s
-        if ageing:
-            args += ' ageing %s' %ageing
-        if learning == 'off':
-            args += ' nolearning'
-
-        if self.link_exists(name):
-            cmd = 'link set dev %s type vxlan dstport %d' %(name, VXLAN_UDP_PORT)
-        else:
-            cmd = 'link add dev %s type vxlan id %s dstport %d' %(name, vxlanid, VXLAN_UDP_PORT)
-        cmd += args
-
-        if self.ipbatch and not self.ipbatch_pause:
-            self.add_to_batch(cmd)
-        else:
-            self.exec_command('ip %s' %cmd)
-
-        # figure out the diff for remotes and do the bridge fdb updates
-        cur_peers = set(self.get_vxlan_peers(name))
-        if remoteips:
-            new_peers = set(remoteips)
-            del_list = cur_peers.difference(new_peers)
-            add_list = new_peers.difference(cur_peers)
-        else:
-            del_list = cur_peers
-            add_list = []
-
-        try:
-            for addr in del_list:
-                self.bridge_fdb_del(name, '00:00:00:00:00:00', None, True, addr)
-        except:
-            pass
-
-        try:
-            for addr in add_list:
-                self.bridge_fdb_append(name, '00:00:00:00:00:00', None, True, addr)
-        except:
-            pass
-
-        # XXX: update linkinfo correctly
-        self._cache_update([name], {})
-
-    def link_exists(self, ifacename):
-        if self.DRYRUN:
-            return True
-        return os.path.exists('/sys/class/net/%s' %ifacename)
-
-    def is_vlan_device_by_name(self, ifacename):
-        if re.search(r'\.', ifacename):
-            return True
-        return False
-
-    def route_add(self, route):
-        self.exec_command('ip route add ' + route)
-
-    def route6_add(self, route):
-        self.exec_command('ip -6 route add ' + route)
-
-    def get_vlandev_attrs(self, ifacename):
-        return (self._cache_get('link', [ifacename, 'linkinfo', 'link']),
-                self._cache_get('link', [ifacename, 'linkinfo', 'vlanid']))
-
-    def get_vxlandev_attrs(self, ifacename):
-        return self._cache_get('link', [ifacename, 'linkinfo'])
-
-    def link_get_mtu(self, ifacename):
-        return self._cache_get('link', [ifacename, 'mtu'])
-
-    def link_get_hwaddress(self, ifacename):
-        address = self._cache_get('link', [ifacename, 'hwaddress'])
-        # newly created logical interface addresses dont end up in the cache
-        # read hwaddress from sysfs file for these interfaces
-        if not address:
-            address = self.read_file_oneline('/sys/class/net/%s/address'
-                                             %ifacename)
-        return address
-
-    def link_create(self, ifacename, type, link=None):
-        if self.link_exists(ifacename):
-            return
-        cmd = 'link add'
-        if link:
-            cmd += ' link %s' %link
-        cmd += ' name %s type %s' %(ifacename, type)
-        if self.ipbatch and not self.ipbatch_pause:
-            self.add_to_batch(cmd)
-        else:
-            self.exec_command('ip %s' %cmd)
-        self._cache_update([ifacename], {})
-
-    def link_delete(self, ifacename):
-        if not self.link_exists(ifacename):
-            return
-        cmd = 'link del %s' %ifacename
-        if self.ipbatch and not self.ipbatch_pause:
-            self.add_to_batch(cmd)
-        else:
-            self.exec_command('ip %s' %cmd)
-        self._cache_invalidate()
-
-    def bridge_port_vids_add(self, bridgeportname, vids):
-        [self.exec_command('bridge vlan add vid %s dev %s'
-                          %(v, bridgeportname)) for v in vids]
-
-    def bridge_port_vids_del(self, bridgeportname, vids):
-        if not vids:
-            return
-        [self.exec_command('bridge vlan del vid %s dev %s'
-                          %(v, bridgeportname)) for v in vids]
-
-    def bridge_port_vids_flush(self, bridgeportname):
-        self.exec_command('bridge vlan del vid %s dev %s'
-                          %(vid, bridgeportname))
-
-    def bridge_port_vids_get(self, bridgeportname):
-        self.exec_command('/bin/bridge vlan show %s' %bridgeportname)
-        bridgeout = self.exec_command('/bin/bridge vlan show dev %s'
-                                      %bridgeportname)
-        if not bridgeout: return []
-        brvlanlines = bridgeout.readlines()[2:]
-        vids = [l.strip() for l in brvlanlines]
-        return [vid for v in vids if vid]
-
-    def bridge_port_vids_get_all(self):
-        brvlaninfo = {}
-        bridgeout = self.exec_command('/bin/bridge vlan show')
-        if not bridgeout: return brvlaninfo
-        brvlanlines = bridgeout.splitlines()
-        brportname=None
-        for l in brvlanlines[1:]:
-            if l and l[0] not in [' ', '\t']:
-                brportname = None
-            l=l.strip()
-            if not l:
-                brportname=None
-                continue
-            if 'PVID' in l:
-                       attrs = l.split()
-                       brportname = attrs[0]
-                       brvlaninfo[brportname] = {'pvid' : attrs[1],
-                                                             'vlan' : []}
-            elif brportname:
-                if 'Egress Untagged' not in l:
-                           brvlaninfo[brportname]['vlan'].append(l)
-            elif not brportname:
-                attrs = l.split()
-                if attrs[1] == 'None' or 'Egress Untagged' in attrs[1]:
-                    continue
-                brportname = attrs[0]
-                brvlaninfo[brportname] = {'vlan' : [attrs[1]]}
-        return brvlaninfo
-
-    def bridge_port_pvid_add(self, bridgeportname, pvid):
-        self.exec_command('bridge vlan add vid %s untagged pvid dev %s'
-                          %(pvid, bridgeportname))
-
-    def bridge_port_pvid_del(self, bridgeportname, pvid):
-        self.exec_command('bridge vlan del vid %s untagged pvid dev %s'
-                          %(pvid, bridgeportname))
-
-    def bridge_port_pvids_get(self, bridgeportname):
-        return self.read_file_oneline('/sys/class/net/%s/brport/pvid'
-                                      %bridgeportname)
-
-    def bridge_vids_add(self, bridgeportname, vids, bridge=True):
-        target = 'self' if bridge else ''
-        [self.exec_command('bridge vlan add vid %s dev %s %s'
-                          %(v, bridgeportname, target)) for v in vids]
-
-    def bridge_vids_del(self, bridgeportname, vids, bridge=True):
-        target = 'self' if bridge else ''
-        [self.exec_command('bridge vlan del vid %s dev %s %s'
-                          %(v, bridgeportname, target)) for v in vids]
-
-    def bridge_fdb_add(self, dev, address, vlan=None, bridge=True, remote=None):
-        target = 'self' if bridge else ''
-        vlan_str = ''
-        if vlan:
-            vlan_str = 'vlan %s ' % vlan
-
-        dst_str = ''
-        if remote:
-            dst_str = 'dst %s ' % remote
-
-        self.exec_command('bridge fdb replace %s dev %s %s %s %s'
-                          %(address, dev, vlan_str, target, dst_str))
-
-    def bridge_fdb_append(self, dev, address, vlan=None, bridge=True, remote=None):
-        target = 'self' if bridge else ''
-        vlan_str = ''
-        if vlan:
-            vlan_str = 'vlan %s ' % vlan
-        dst_str = ''
-        if remote:
-            dst_str = 'dst %s ' % remote
-
-        self.exec_command('bridge fdb append %s dev %s %s %s %s'
-                          %(address, dev, vlan_str, target, dst_str))
-
-    def bridge_fdb_del(self, dev, address, vlan=None, bridge=True, remote=None):
-        target = 'self' if bridge else ''
-        vlan_str = ''
-        if vlan:
-            vlan_str = 'vlan %s ' % vlan
-
-        dst_str = ''
-        if remote:
-            dst_str = 'dst %s ' % remote
-        self.exec_command('bridge fdb del %s dev %s %s %s %s'
-                          %(address, dev, vlan_str, target, dst_str))
-
-    def bridge_is_vlan_aware(self, bridgename):
-        filename = '/sys/class/net/%s/bridge/vlan_filtering' %bridgename
-        if os.path.exists(filename) and self.read_file_oneline(filename) == '1':
-            return True
-        return False
-
-    def bridge_port_get_bridge_name(self, bridgeport):
-        filename = '/sys/class/net/%s/brport/bridge' %bridgeport
-        try:
-            return os.path.basename(os.readlink(filename))
-        except:
-            return None
-
-    def bridge_port_exists(self, bridge, bridgeportname):
-        try:
-            return os.path.exists('/sys/class/net/%s/brif/%s'
-                                  %(bridge, bridgeportname))
-        except Exception:
-            return False
-
-    def bridge_fdb_show_dev(self, dev):
-        try:
-            fdbs = {}
-            output = self.exec_command('bridge fdb show dev %s' %dev)
-            if output:
-                for fdb_entry in output.splitlines():
-                    try:
-                        entries = fdb_entry.split()
-                        fdbs.setdefault(entries[2], []).append(entries[0])
-                    except:
-                        self.logger.debug('%s: invalid fdb line \'%s\''
-                                %(dev, fdb_entry))
-                        pass
-            return fdbs
-        except Exception:
-            return None
-
-    def is_bridge(self, bridge):
-        return os.path.exists('/sys/class/net/%s/bridge' %bridge)
-
-    def is_link_up(self, ifacename):
-        ret = False
-        try:
-            flags = self.read_file_oneline('/sys/class/net/%s/flags' %ifacename)
-            iflags = int(flags, 16)
-            if (iflags & 0x0001):
-                ret = True
-        except: 
-            ret = False
-            pass
-        return ret
-
-    def ip_route_get_dev(self, prefix):
-        try:
-            output = self.exec_command('ip route get %s' %prefix)
-            if output:
-               rline = output.splitlines()[0]
-               if rline:
-                    rattrs = rline.split()
-                    return rattrs[rattrs.index('dev') + 1]
-        except Exception, e:
-            self.logger.debug('ip_route_get_dev: failed .. %s' %str(e))
-            pass
-        return None
diff --git a/ifupdown2/ifupdownaddons/modulebase.py b/ifupdown2/ifupdownaddons/modulebase.py
deleted file mode 100644 (file)
index 47df790..0000000
+++ /dev/null
@@ -1,363 +0,0 @@
-#!/usr/bin/python
-#
-# Copyright 2014 Cumulus Networks, Inc. All rights reserved.
-# Author: Roopa Prabhu, roopa@cumulusnetworks.com
-#
-
-import os
-import re
-import io
-import logging
-import subprocess
-import traceback
-from ifupdown.iface import *
-#from ifupdownaddons.iproute2 import *
-#from ifupdownaddons.dhclient import *
-#from ifupdownaddons.bridgeutils import *
-#from ifupdownaddons.mstpctlutil import *
-#from ifupdownaddons.ifenslaveutil import *
-
-class moduleBase(object):
-    """ Base class for ifupdown addon modules
-
-    Provides common infrastructure methods for all addon modules """
-
-    def __init__(self, *args, **kargs):
-        modulename = self.__class__.__name__
-        self.logger = logging.getLogger('ifupdown.' + modulename)
-        self.FORCE = kargs.get('force', False)
-        """force interface configuration"""
-        self.DRYRUN = kargs.get('dryrun', False)
-        """only predend you are applying configuration, dont really do it"""
-        self.NOWAIT = kargs.get('nowait', False)
-        self.PERFMODE = kargs.get('perfmode', False)
-        self.CACHE = kargs.get('cache', False)
-        self.CACHE_FLAGS = kargs.get('cacheflags', 0x0)
-
-    def log_warn(self, str):
-        """ log a warning if err str is not one of which we should ignore """
-        if not self.ignore_error(str):
-            if self.logger.getEffectiveLevel() == logging.DEBUG:
-                traceback.print_stack()
-            self.logger.warn(str)
-        pass
-
-    def log_error(self, str):
-        """ log an err if err str is not one of which we should ignore and raise an exception """
-        if not self.ignore_error(str):
-            if self.logger.getEffectiveLevel() == logging.DEBUG:
-                traceback.print_stack()
-            raise Exception(str)
-        else:
-            pass
-
-    def is_process_running(self, procName):
-        try:
-            self.exec_command('/bin/pidof -x %s' % procName)
-        except:
-            return False
-        else:
-            return True
-
-    def exec_command(self, cmd, cmdenv=None):
-        """ execute command passed as argument.
-
-        Args:
-            cmd (str): command to execute
-
-        Kwargs:
-            cmdenv (dict): environment variable name value pairs
-        """
-        cmd_returncode = 0
-        cmdout = ''
-
-        try:
-            self.logger.info('Executing ' + cmd)
-            if self.DRYRUN:
-                return cmdout
-            ch = subprocess.Popen(cmd.split(),
-                    stdout=subprocess.PIPE,
-                    shell=False, env=cmdenv,
-                    stderr=subprocess.STDOUT,
-                    close_fds=True)
-            cmdout = ch.communicate()[0]
-            cmd_returncode = ch.wait()
-        except OSError, e:
-            raise Exception('could not execute ' + cmd +
-                    '(' + str(e) + ')')
-        if cmd_returncode != 0:
-            raise Exception('error executing cmd \'%s\'' %cmd +
-                '(' + cmdout.strip('\n ') + ')')
-        return cmdout
-
-    def exec_command_talk_stdin(self, cmd, stdinbuf):
-        """ execute command passed as argument and write contents of stdinbuf
-        into stdin of the cmd
-
-        Args:
-            cmd (str): command to execute
-            stdinbuf (str): string to write to stdin of the cmd process
-        """
-        cmd_returncode = 0
-        cmdout = ''
-
-        try:
-            self.logger.info('Executing %s (stdin=%s)' %(cmd, stdinbuf))
-            if self.DRYRUN:
-                return cmdout
-            ch = subprocess.Popen(cmd.split(),
-                    stdout=subprocess.PIPE,
-                    stdin=subprocess.PIPE,
-                    shell=False, env=cmdenv,
-                    stderr=subprocess.STDOUT,
-                    close_fds=True)
-            cmdout = ch.communicate(input=stdinbuf)[0]
-            cmd_returncode = ch.wait()
-        except OSError, e:
-            raise Exception('could not execute ' + cmd +
-                    '(' + str(e) + ')')
-        if cmd_returncode != 0:
-            raise Exception('error executing cmd \'%s (%s)\''
-                    %(cmd, stdinbuf) + '(' + cmdout.strip('\n ') + ')')
-        return cmdout
-
-    def get_ifaces_from_proc(self):
-        ifacenames = []
-        with open('/proc/net/dev') as f:
-            try:
-                lines = f.readlines()
-                for line in lines:
-                    ifacenames.append(line.split()[0].strip(': '))
-            except:
-                raise
-        return ifacenames
-
-    def parse_regex(self, expr, ifacenames=None):
-        try:
-            proc_ifacenames = self.get_ifaces_from_proc()
-        except:
-            self.logger.warn('error reading ifaces from proc')
-        for proc_ifacename in proc_ifacenames:
-            if re.search(expr + '$', proc_ifacename):
-                yield proc_ifacename
-        if not ifacenames:
-            return
-        for ifacename in ifacenames:
-            if re.search(expr + '$', ifacename):
-                yield ifacename
-
-    def parse_glob(self, expr):
-        errmsg = ('error parsing glob expression \'%s\'' %expr +
-                    ' (supported glob syntax: swp1-10 or swp[1-10])')
-        start_index = 0
-        end_index = 0
-        try:
-            regexs = [re.compile(r"([A-Za-z0-9\-]+[A-Za-z])(\d+)\-(\d+)(.*)"),
-                      re.compile(r"([A-Za-z0-9\-]+)\[(\d+)\-(\d+)\](.*)")]
-            for r in regexs:
-                m = r.match(expr)
-                if not m:
-                    continue
-                mlist = m.groups()
-                if len(mlist) != 4:
-                    raise Exception(errmsg + '(unexpected len)')
-                prefix = mlist[0]
-                suffix = mlist[3]
-                start_index = int(mlist[1])
-                end_index = int(mlist[2])
-        except:
-            self.logger.warn(errmsg)
-            pass
-        if not start_index and not end_index:
-            self.logger.warn(errmsg)
-            yield expr
-        else:
-            for i in range(start_index, end_index + 1):
-                yield prefix + '%d' %i + suffix
-
-    def parse_port_list(self, port_expr, ifacenames=None):
-        """ parse port list containing glob and regex
-
-        Args:
-            port_expr (str): expression
-            ifacenames (list): list of interface names. This needs to be specified if the expression has a regular expression
-        """
-        regex = 0
-        glob = 0
-        portlist = []
-
-        if not port_expr:
-            return None
-        for expr in re.split(r'[\s\t]\s*', port_expr):
-            if expr == 'noregex':
-                regex = 0
-            elif expr == 'noglob':
-                glob = 0
-            elif expr == 'regex':
-                regex = 1
-            elif expr == 'glob':
-                glob = 1
-            elif regex:
-                for port in self.parse_regex(expr, ifacenames):
-                    if port not in portlist:
-                        portlist.append(port)
-                regex = 0
-            elif glob:
-                for port in self.parse_glob(expr):
-                    portlist.append(port)
-                glob = 0
-            else:
-                portlist.append(expr)
-        if not portlist:
-            return None
-        return portlist
-
-    def ignore_error(self, errmsg):
-        if (self.FORCE or re.search(r'exists', errmsg,
-            re.IGNORECASE | re.MULTILINE)):
-            return True
-        return False
-
-    def write_file(self, filename, strexpr):
-        """ writes string to a file """
-        try:
-            self.logger.info('writing \'%s\'' %strexpr +
-                ' to file %s' %filename)
-            if self.DRYRUN:
-                return 0
-            with open(filename, 'w') as f:
-                f.write(strexpr)
-        except IOError, e:
-            self.logger.warn('error writing to file %s'
-                %filename + '(' + str(e) + ')')
-            return -1
-        return 0
-
-    def read_file(self, filename):
-        """ read file and return lines from the file """
-        try:
-            self.logger.info('reading \'%s\'' %filename)
-            with open(filename, 'r') as f:
-                return f.readlines()
-        except:
-            return None
-        return None
-
-    def read_file_oneline(self, filename):
-        """ reads and returns first line from the file """
-        try:
-            self.logger.info('reading \'%s\'' %filename)
-            with open(filename, 'r') as f:
-                return f.readline().strip('\n')
-        except:
-            return None
-        return None
-
-    def sysctl_set(self, variable, value):
-        """ set sysctl variable to value passed as argument """
-        self.exec_command('sysctl %s=' %variable + '%s' %value)
-
-    def sysctl_get(self, variable):
-        """ get value of sysctl variable """
-        return self.exec_command('sysctl %s' %variable).split('=')[1].strip()
-
-    def set_iface_attr(self, ifaceobj, attr_name, attr_valsetfunc,
-                       prehook=None, prehookargs=None):
-        ifacename = ifaceobj.name
-        attrvalue = ifaceobj.get_attr_value_first(attr_name)
-        if attrvalue:
-            if prehook:
-                if prehookargs:
-                    prehook(prehookargs)
-                else:
-                    prehook(ifacename)
-            attr_valsetfunc(ifacename, attrvalue)
-
-    def query_n_update_ifaceobjcurr_attr(self, ifaceobj, ifaceobjcurr,
-                                       attr_name, attr_valgetfunc,
-                                       attr_valgetextraarg=None):
-        attrvalue = ifaceobj.get_attr_value_first(attr_name)
-        if not attrvalue:
-            return
-        if attr_valgetextraarg:
-            runningattrvalue = attr_valgetfunc(ifaceobj.name,
-                                             attr_valgetextraarg)
-        else:
-            runningattrvalue = attr_valgetfunc(ifaceobj.name)
-        if (not runningattrvalue or
-            (runningattrvalue != attrvalue)):
-            ifaceobjcurr.update_config_with_status(attr_name,
-                runningattrvalue, 1)
-        else:
-            ifaceobjcurr.update_config_with_status(attr_name,
-                runningattrvalue, 0)
-
-    def dict_key_subset(self, a, b): 
-        """ returns a list of differing keys """
-        return [x for x in a if x in b]
-
-    def get_mod_attrs(self):
-        """ returns list of all module attrs defined in the module _modinfo dict"""
-        try:
-            return self._modinfo.get('attrs').keys()
-        except:
-            return None
-
-    def get_mod_attr(self, attrname):
-        """ returns module attr info """
-        try:
-            return self._modinfo.get('attrs', {}).get(attrname)
-        except:
-            return None
-
-    def get_mod_subattr(self, attrname, subattrname):
-        """ returns module attrs defined in the module _modinfo dict"""
-        try:
-            return reduce(lambda d, k: d[k], ['attrs', attrname, subattrname],
-                         self._modinfo)
-        except:
-            return None
-
-    def get_modinfo(self):
-        """ return module info """
-        try:
-            return self._modinfo
-        except:
-            return None
-
-    def get_flags(self):
-        return dict(force=self.FORCE, dryrun=self.DRYRUN, nowait=self.NOWAIT,
-                    perfmode=self.PERFMODE, cache=self.CACHE,
-                    cacheflags=self.CACHE_FLAGS)
-
-    def _get_reserved_vlan_range(self):
-        start = end = 0
-        get_resvvlan = '/usr/share/python-ifupdown2/get_reserved_vlan_range.sh'
-        if not os.path.exists(get_resvvlan):
-            return (start, end)
-        try:
-            (s, e) = self.exec_command(get_resvvlan).strip('\n').split('-')
-            start = int(s)
-            end = int(e)
-        except Exception, e:
-            self.logger.debug('%s failed (%s)' %(get_resvvlan, str(e)))
-            # ignore errors
-            pass
-        return (start, end)
-
-    def _handle_reserved_vlan(self, vlanid, logprefix=''):
-        """ Helper function to check and warn if the vlanid falls in the
-        reserved vlan range """
-        if vlanid in range(self._resv_vlan_range[0],
-                           self._resv_vlan_range[1]):
-           self.logger.error('%s: reserved vlan %d being used'
-                   %(logprefix, vlanid) + ' (reserved vlan range %d-%d)'
-                   %(self._resv_vlan_range[0], self._resv_vlan_range[1]))
-           return True
-        return False
-
-    def _valid_ethaddr(self, ethaddr):
-        """ Check if address is 00:00:00:00:00:00 """
-        if not ethaddr or re.match('00:00:00:00:00:00', ethaddr):
-            return False
-        return True
diff --git a/ifupdown2/ifupdownaddons/mstpctlutil.py b/ifupdown2/ifupdownaddons/mstpctlutil.py
deleted file mode 100644 (file)
index 4716195..0000000
+++ /dev/null
@@ -1,171 +0,0 @@
-#!/usr/bin/python
-#
-# Copyright 2014 Cumulus Networks, Inc. All rights reserved.
-# Author: Roopa Prabhu, roopa@cumulusnetworks.com
-#
-
-from utilsbase import *
-from ifupdown.iface import *
-from cache import *
-import re
-
-class mstpctlutil(utilsBase):
-    """ This class contains helper methods to interact with mstpd using
-    mstputils commands """
-
-    _cache_fill_done = False
-
-    _bridgeattrmap = {'bridgeid' : 'bridge-id',
-                     'maxage' : 'max-age',
-                     'fdelay' : 'forward-delay',
-                     'txholdcount' : 'tx-hold-count',
-                     'maxhops' : 'max-hops',
-                     'ageing' : 'ageing-time',
-                     'hello' : 'hello-time',
-                     'forcevers' : 'force-protocol-version'}
-
-    _bridgeportattrmap = {'portadminedge' : 'admin-edge-port',
-                     'portp2p' : 'admin-point-to-point',
-                     'portrestrrole' : 'restricted-role',
-                     'portrestrtcn' : 'restricted-TCN',
-                     'bpduguard' : 'bpdu-guard-port',
-                     'portautoedge' : 'auto-edge-port',
-                     'portnetwork' : 'network-port',
-                     'portbpdufilter' : 'bpdufilter-port'}
-
-    def __init__(self, *args, **kargs):
-        utilsBase.__init__(self, *args, **kargs)
-
-    def is_mstpd_running(self):
-        try:
-            self.exec_command('/bin/pidof mstpd')
-        except:
-            return False
-        else:
-            return True
-
-    def get_bridgeport_attr(self, bridgename, portname, attrname):
-        try:
-            return self.subprocess_check_output(['/sbin/mstpctl',
-                       'showportdetail', '%s' %bridgename, '%s' %portname,
-                       self._bridgeportattrmap[attrname]]).strip('\n')
-        except Exception, e:
-            pass
-        return None
-
-    def get_bridgeport_attrs(self, bridgename, portname):
-        bridgeattrs = {}
-        try:
-            bridgeattrs = dict((k, self.get_bridgeport_attr(bridgename, v))
-                                 for k, v in self._bridgeattrmap.items())
-            bridgeattrs['treeprio'] = int(bridgeattrs.get('bridgeid',
-                                     '').split('.')[0], base=16) * 4096
-        except Exception, e:
-            self.logger.warn(str(e))
-            pass
-        return bridgeattrs
-
-    def set_bridgeport_attrs(self, bridgename, bridgeportname, attrdict,
-                             check=True):
-        for k, v in attrdict.iteritems():
-            if not v:
-                continue
-            try:
-                self.set_bridgeport_attr(self, bridgename, bridgeportname,
-                        k, v, check)
-            except Exception, e:
-                self.logger.warn(str(e))
-
-    def set_bridgeport_attr(self, bridgename, bridgeportname, attrname,
-                            attrvalue, check=True):
-        if check:
-            attrvalue_curr = self.get_bridgeport_attr(bridgename,
-                                    bridgeportname, attrname)
-            if attrvalue_curr and attrvalue_curr == attrvalue:
-                return
-        if attrname == 'treeportcost' or attrname == 'treeportprio':
-            self.subprocess_check_output(['/sbin/mstpctl', 'set%s' %attrname,
-                  '%s' %bridgename, '%s' %bridgeportname, '0', '%s' %attrvalue])
-        else:
-            self.subprocess_check_output(['/sbin/mstpctl', 'set%s' %attrname,
-                  '%s' %bridgename, '%s' %bridgeportname, '%s' %attrvalue])
-
-    def get_bridge_attrs(self, bridgename):
-        bridgeattrs = {}
-        try:
-            bridgeattrs = dict((k, self.get_bridge_attr(bridgename, k))
-                                 for k in self._bridgeattrmap.keys())
-            bridgeattrs['treeprio'] = '%d' %(int(bridgeattrs.get('bridgeid',
-                                     '').split('.')[0], base=16) * 4096)
-            del bridgeattrs['bridgeid']
-        except Exception, e:
-            self.logger.debug(bridgeattrs)
-            self.logger.debug(str(e))
-            pass
-        return bridgeattrs
-
-    def get_bridge_attr(self, bridgename, attrname):
-        try:
-            return self.subprocess_check_output(['/sbin/mstpctl',
-                       'showbridge', '%s' %bridgename,
-                       self._bridgeattrmap[attrname]]).strip('\n')
-        except Exception, e:
-            pass
-        return None
-
-    def set_bridge_attr(self, bridgename, attrname, attrvalue, check=True):
-
-        if check:
-            attrvalue_curr = self.get_bridge_attr(bridgename, attrname)
-            if attrvalue_curr and attrvalue_curr == attrvalue:
-                return
-        if attrname == 'treeprio':
-            self.subprocess_check_call(['/sbin/mstpctl', 'set%s' %attrname,
-                        '%s' %bridgename, '0',  '%s' %attrvalue])
-        else:
-            self.subprocess_check_call(['/sbin/mstpctl', 'set%s' %attrname,
-                        '%s' %bridgename, '%s' %attrvalue])
-
-    def set_bridge_attrs(self, bridgename, attrdict, check=True):
-        for k, v in attrdict.iteritems():
-            if not v:
-                continue
-            try:
-                self.set_bridge_attr(bridgename, k, v, check)
-            except Exception, e:
-                self.logger.warn('%s: %s' %(bridgename, str(e)))
-                pass
-
-    def get_bridge_treeprio(self, bridgename):
-        try:
-            bridgeid = subprocess.check_output(['/sbin/mstpctl',
-                       'showbridge', '%s' %bridgename,
-                       self._bridgeattrmap['bridgeid']]).strip('\n')
-            return '%d' %(int(bridgeid.split('.')[0], base=16) * 4096)
-        except:
-            pass
-        return None
-
-    def set_bridge_treeprio(self, bridgename, attrvalue, check=True):
-        if check:
-            attrvalue_curr = self.get_bridge_treeprio(bridgename)
-            if attrvalue_curr and attrvalue_curr == attrvalue:
-                return
-        self.subprocess_check_output(['/sbin/mstpctl', 'settreeprio',
-                        '%s' %bridgename, '0',  '%s' %attrvalue])
-
-    def showbridge(self, bridgename=None):
-        if bridgename:
-            return self.exec_command('/sbin/mstpctl showbridge %s' %bridgename)
-        else:
-            return self.exec_command('/sbin/mstpctl showbridge')
-
-    def showportdetail(self, bridgename):
-        return self.exec_command('/sbin/mstpctl showportdetail %s' %bridgename)
-
-    def mstpbridge_exists(self, bridgename):
-        try:
-            subprocess.check_call('mstpctl showbridge %s' %bridgename)
-            return True
-        except:
-            return False
diff --git a/ifupdown2/ifupdownaddons/utilsbase.py b/ifupdown2/ifupdownaddons/utilsbase.py
deleted file mode 100644 (file)
index 73fdfd5..0000000
+++ /dev/null
@@ -1,163 +0,0 @@
-#!/usr/bin/python
-#
-# Copyright 2014 Cumulus Networks, Inc. All rights reserved.
-# Author: Roopa Prabhu, roopa@cumulusnetworks.com
-#
-
-import logging
-import subprocess
-import re
-import io
-from ifupdown.iface import *
-from cache import *
-
-#import timeit
-import time
-import logging
-
-def profile(func):
-    def wrap(*args, **kwargs):
-        started_at = time.time()
-        result = func(*args, **kwargs)
-        print str(func)
-        print (time.time() - started_at)
-        return result
-    return wrap
-
-class utilsBase(object):
-    """ Base class for ifupdown addon utilities """
-
-    def __init__(self, *args, **kargs):
-        modulename = self.__class__.__name__
-        self.logger = logging.getLogger('ifupdown.' + modulename)
-        self.FORCE = kargs.get('force', False)
-        self.DRYRUN = kargs.get('dryrun', False)
-        self.NOWAIT = kargs.get('nowait', False)
-        self.PERFMODE = kargs.get('perfmode', False)
-        self.CACHE = kargs.get('cache', False)
-
-    def exec_commandl(self, cmdl, cmdenv=None):
-        """ Executes command """
-
-        cmd_returncode = 0
-        cmdout = ''
-        try:
-            self.logger.info('executing ' + ' '.join(cmdl))
-            if self.DRYRUN:
-                return cmdout
-            ch = subprocess.Popen(cmdl,
-                    stdout=subprocess.PIPE,
-                    shell=False, env=cmdenv,
-                    stderr=subprocess.STDOUT,
-                    close_fds=True)
-            cmdout = ch.communicate()[0]
-            cmd_returncode = ch.wait()
-        except OSError, e:
-            raise Exception('failed to execute cmd \'%s\' (%s)'
-                            %(' '.join(cmdl), str(e)))
-        if cmd_returncode != 0:
-            raise Exception('failed to execute cmd \'%s\''
-                 %' '.join(cmdl) + '(' + cmdout.strip('\n ') + ')')
-        return cmdout
-
-    def exec_command(self, cmd, cmdenv=None):
-        """ Executes command given as string in the argument cmd """
-
-        return self.exec_commandl(cmd.split(), cmdenv)
-
-    def exec_command_talk_stdin(self, cmd, stdinbuf):
-        """ Executes command and writes to stdin of the process """
-        cmd_returncode = 0
-        cmdout = ''
-        try:
-            self.logger.info('executing %s [%s]' %(cmd, stdinbuf))
-            if self.DRYRUN:
-                return cmdout
-            ch = subprocess.Popen(cmd.split(),
-                    stdout=subprocess.PIPE,
-                    stdin=subprocess.PIPE,
-                    shell=False,
-                    stderr=subprocess.STDOUT,
-                    close_fds=True)
-            cmdout = ch.communicate(input=stdinbuf)[0]
-            cmd_returncode = ch.wait()
-        except OSError, e:
-            raise Exception('failed to execute cmd \'%s\' (%s)'
-                            %(cmd, str(e)))
-        if cmd_returncode != 0:
-            raise Exception('failed to execute cmd \'%s [%s]\''
-                %(cmd, stdinbuf) + '(' + cmdout.strip('\n ') + ')')
-        return cmdout
-
-    def subprocess_check_output(self, cmdl):
-        self.logger.info('executing ' + ' '.join(cmdl))
-        if self.DRYRUN:
-            return
-        try:
-            return subprocess.check_output(cmdl, stderr=subprocess.STDOUT)
-        except Exception, e:
-            raise Exception('failed to execute cmd \'%s\' (%s)'
-                        %(' '.join(cmdl), e.output))
-
-    def subprocess_check_call(self, cmdl):
-        """ subprocess check_call implementation using popen
-        
-        Uses popen because it needs the close_fds argument
-        """
-
-        cmd_returncode = 0
-        try:
-            self.logger.info('executing ' + ' '.join(cmdl))
-            if self.DRYRUN:
-                return
-            ch = subprocess.Popen(cmdl,
-                    stdout=None,
-                    shell=False,
-                    stderr=None,
-                    close_fds=True)
-            cmd_returncode = ch.wait()
-        except Exception, e:
-            raise Exception('failed to execute cmd \'%s\' (%s)'
-                            %(' '.join(cmdl), str(e)))
-        if cmd_returncode != 0:
-            raise Exception('failed to execute cmd \'%s\''
-                 %' '.join(cmdl))
-        return
-
-    def write_file(self, filename, strexpr):
-        try:
-            self.logger.info('writing \'%s\'' %strexpr +
-                ' to file %s' %filename)
-            if self.DRYRUN:
-                return 0
-            with open(filename, 'w') as f:
-                f.write(strexpr)
-        except IOError, e:
-            self.logger.warn('error writing to file %s'
-                %filename + '(' + str(e) + ')')
-            return -1
-        return 0
-
-    def read_file(self, filename):
-        try:
-            self.logger.debug('reading \'%s\'' %filename)
-            with open(filename, 'r') as f:
-                return f.readlines()
-        except:
-            return None
-        return None
-
-    def read_file_oneline(self, filename):
-        try:
-            self.logger.debug('reading \'%s\'' %filename)
-            with open(filename, 'r') as f:
-                return f.readline().strip('\n')
-        except:
-            return None
-        return None
-
-    def sysctl_set(self, variable, value):
-        self.exec_command('sysctl %s=' %variable + '%s' %value)
-
-    def sysctl_get(self, variable):
-        return self.exec_command('sysctl %s' %variable).split('=')[1].strip()
diff --git a/ifupdown2/init.d/networking b/ifupdown2/init.d/networking
deleted file mode 100644 (file)
index 45d3d78..0000000
+++ /dev/null
@@ -1,218 +0,0 @@
-#!/bin/bash
-### BEGIN INIT INFO
-# Provides:          networking ifupdown
-# Required-Start:    mountkernfs $local_fs urandom
-# Required-Stop:     $local_fs
-# Default-Start:     S
-# Default-Stop:      0 6
-# Short-Description: Raise network interfaces.
-# Description:       Prepare /run/network directory, ifstate file and raise network interfaces, or take them down.
-### END INIT INFO
-
-PATH="/sbin:/bin"
-RUN_DIR="/run/network"
-IFSTATE="$RUN_DIR/ifstate"
-
-NAME=networking
-SCRIPTNAME=/etc/init.d/$NAME
-
-[ -x /sbin/ifup ] || exit 0
-[ -x /sbin/ifdown ] || exit 0
-
-. /lib/lsb/init-functions
-
-CONFIGURE_INTERFACES=yes
-
-EXTRA_ARGS=
-
-[ -f /etc/default/networking ] && . /etc/default/networking
-
-[ "$VERBOSE" = yes ] && EXTRA_ARGS=-v
-[ "$DEBUG" = yes ] && EXTRA_ARGS="$EXTRA_ARGS -d"
-[ "$SYSLOG" = yes ] && EXTRA_ARGS="$EXTRA_ARGS --syslog"
-
-gen_examples() {
-    # Generate sample interfaces file. The interfaces files are
-    # generated under /usr/share/doc/python-ifupdown2/examples/
-    #
-
-    # generate files only at boot
-    [ -f /var/tmp/network/ifstatenew ] && return
-
-    python_ifupdown2_docdir="/usr/share/doc/python-ifupdown2"
-    swpfile=${python_ifupdown2_docdir}"/examples/swp_defaults"
-    bridgedefaultfile=${python_ifupdown2_docdir}"/examples/bridge_untagged_default"
-    interfaces_gen_script=${python_ifupdown2_docdir}"/examples/generate_interfaces.py"
-
-    [ ! -e $interfaces_gen_script ] && return
-    ret=$($interfaces_gen_script -s 2>&1 >$swpfile)
-    ret=$($interfaces_gen_script -b 2>&1 >$bridgedefaultfile)
-    return
-}
-
-perf_options() {
-    # At bootup lets set perfmode
-    [ -f /var/tmp/network/ifstatenew ] && echo -n "" && return
-
-    echo -n "--perfmode"
-}
-
-process_exclusions() {
-    set -- $EXCLUDE_INTERFACES
-    exclusions=""
-    for d
-    do
-       exclusions="-X $d $exclusions"
-    done
-    echo $exclusions
-}
-
-check_network_file_systems() {
-    [ -e /proc/mounts ] || return 0
-
-    if [ -e /etc/iscsi/iscsi.initramfs ]; then
-       log_warning_msg "not deconfiguring network interfaces: iSCSI root is mounted."
-       exit 0
-    fi
-
-    while read DEV MTPT FSTYPE REST; do
-       case $DEV in
-       /dev/nbd*|/dev/nd[a-z]*|/dev/etherd/e*)
-           log_warning_msg "not deconfiguring network interfaces: network devices still mounted."
-           exit 0
-           ;;
-       esac
-       case $FSTYPE in
-       nfs|nfs4|smbfs|ncp|ncpfs|cifs|coda|ocfs2|gfs|pvfs|pvfs2|fuse.httpfs|fuse.curlftpfs)
-           log_warning_msg "not deconfiguring network interfaces: network file systems still mounted."
-           exit 0
-           ;;
-       esac
-    done < /proc/mounts
-}
-
-check_network_swap() {
-    [ -e /proc/swaps ] || return 0
-
-    while read DEV MTPT FSTYPE REST; do
-       case $DEV in
-       /dev/nbd*|/dev/nd[a-z]*|/dev/etherd/e*)
-           log_warning_msg "not deconfiguring network interfaces: network swap still mounted."
-           exit 0
-           ;;
-       esac
-    done < /proc/swaps
-}
-
-ifup_hotplug () {
-    if [ -d /sys/class/net ]
-    then
-           ifaces=$(for iface in $(ifquery --list --allow=hotplug 2>/dev/null)
-                           do
-                                   link=${iface##:*}
-                                   link=${link##.*}
-                                   if [ -e "/sys/class/net/$link" ] && [ "$(cat /sys/class/net/$link/operstate)" = up ]
-                                   then
-                                           echo "$iface"
-                                   fi
-                           done)
-           if [ -n "$ifaces" ]
-           then
-               ifup $ifaces "$@" || true
-           fi
-    fi
-}
-
-ifupdown_init() {
-       [ ! -e /run/network ] && mkdir -p /run/network &>/dev/null
-       [ ! -e /etc/network/run ] && \
-               ln -sf /run/network /etc/network/run &>/dev/null
-}
-
-case "$1" in
-start)
-       gen_examples
-       ifupdown_init
-       if [ "$CONFIGURE_INTERFACES" = no ]
-       then
-           log_action_msg "Not configuring network interfaces, see /etc/default/networking"
-           exit 0
-       fi
-       set -f
-       exclusions=$(process_exclusions)
-       perfoptions=$(perf_options)
-       log_action_begin_msg "Configuring network interfaces"
-       ifup -a $EXTRA_ARGS $exclusions $perfoptions 
-       log_action_end_msg $?
-       ;;
-
-stop)
-       if [ "$SKIP_DOWN_AT_SYSRESET" = "yes" ]; then
-               shutdown_or_reboot=$(runlevel 2>/dev/null | \
-                                    /usr/bin/tr -s " " | \
-                                    /usr/bin/cut -d " " \
-                                    -f1- --output-delimiter=$'\n' | \
-                                    /bin/grep -e "0" -e "6")
-               if [ -n "$shutdown_or_reboot" ]; then
-                       log_action_begin_msg "Deconfiguring network interfaces..skip"
-                       log_action_end_msg 0
-                       exit 0
-               fi
-       fi
-       ifupdown_init
-       check_network_file_systems
-       check_network_swap
-       exclusions=$(process_exclusions)
-
-       log_action_begin_msg "Deconfiguring network interfaces"
-       ifdown -a $EXTRA_ARGS $exclusions
-       log_action_end_msg $?
-       ;;
-
-reload)
-
-       ifupdown_init
-       log_action_begin_msg "Reloading network interfaces configuration"
-
-       ifreload -a $EXTRA_ARGS
-       log_action_end_msg $?
-       ;;
-
-reload-currently-up)
-
-       ifupdown_init
-       log_action_begin_msg "Reloading currently up network interfaces configuration"
-
-       ifreload --currently-up $EXTRA_ARGS
-       log_action_end_msg $?
-       ;;
-
-force-reload)
-
-       ifupdown_init
-
-       log_action_begin_msg "Reloading network interfaces configuration"
-       ifreload -f -a $EXTRA_ARGS
-       log_action_end_msg $?
-       ;;
-
-restart)
-       ifupdown_init
-
-       set -f
-       exclusions=$(process_exclusions)
-       log_action_begin_msg "Reconfiguring network interfaces"
-       ifdown -a $EXTRA_ARGS $exclusions || true
-       ifup -a $EXTRA_ARGS $exclusions
-       log_action_end_msg $?
-       ;;
-
-*)
-       echo "Usage: /etc/init.d/networking {start|stop|reload|restart|force-reload}"
-       exit 1
-       ;;
-esac
-
-exit 0
-
-# vim: noet ts=8
diff --git a/ifupdown2/man.rst/ifquery.8.rst b/ifupdown2/man.rst/ifquery.8.rst
deleted file mode 100644 (file)
index ba443ce..0000000
+++ /dev/null
@@ -1,151 +0,0 @@
-=======
-ifquery
-=======
-
--------------------------------------
-query network interface configuration
--------------------------------------
-
-:Author: Roopa Prabhu <roopa@cumulusnetworks.com>
-:Date:   2014-02-05
-:Copyright: Copyright 2014 Cumulus Networks, Inc.  All rights reserved.
-:Version: 0.1
-:Manual section: 8
-
-SYNOPSIS
-========
-
-    **ifquery [-v] [--allow CLASS] [--with-depends] -a|IFACE...**
-
-    **ifquery [-v] [-r|--running] [--allow CLASS] [--with-depends] -a|IFACE...**
-
-    **ifquery [-v] [-c|--check] [--allow CLASS] [--with-depends] -a|IFACE...**
-
-    **ifquery [-v] [-p|--print-dependency {list,dot}] [--allow CLASS] [--with-depends] -a|IFACE...**
-
-    **ifquery [-v] -s|--syntax-help**
-
-DESCRIPTION
-===========
-    **ifquery** can be used to parse interface configuration file, query
-    running state or check running state of the interface with configuration
-    in **/etc/network/interfaces** file.
-
-    **ifquery** always works on the current **interfaces(5)** file
-    **/etc/network/interfaces** unless an alternate interfaces file is
-    provided with the **-i** option.
-
-OPTIONS
-=======
-    positional arguments:
-
-    **IFACE**   interface list separated by spaces. **IFACE** list and **'-a'** argument are mutually exclusive.
-
-    optional arguments:
-
-    -h, --help            show this help message and exit
-
-    -a, --all             process all interfaces marked "auto"
-
-    -v, --verbose         verbose
-
-    -d, --debug           output debug info
-    --allow CLASS         ignore non-"allow-CLASS" interfaces
-
-    -w, --with-depends    run with all dependent interfaces. This option
-                          is redundant when -a is specified. When '-a' is
-                          specified, interfaces are always executed in
-                          dependency order.
-
-    -X EXCLUDEPATS, --exclude EXCLUDEPATS
-                          Exclude interfaces from the list of interfaces to
-                          operate on. Can be specified multiple times
-
-    -i INTERFACESFILE, --interfaces INTERFACESFILE
-                          Use interfaces file instead of default
-                          /etc/network/interfaces
-
-    -t {native,json}, --interfaces-format {native,json}
-                          interfaces file format
-
-    -r, --running         print raw interfaces file entries
-
-    -c, --check           check interface file contents against running state
-                          of an interface. Returns exit code 0 on success and
-                          1 on error
-
-    -x, --raw             print raw config file entries
-
-    -o {native,json}, --format {native,json}
-                          interface display format
-
-    -p, --print-dependency {list,dot}
-                          print iface dependency in list or dot format
-
-    -s, --syntax-help     print supported interface config syntax. Scans all
-                          addon modules and dumps supported syntax from them
-                          if provided by the module.
-
-EXAMPLES
-========
-    # dump all or some interfaces config file entries
-    # (pretty prints user provided entries)
-
-        **ifquery -a**
-
-        **ifquery br0**
-
-    # Same as above but dump with dependencies
-
-        **ifquery br0 --with-depends**
-
-    # Check running state with the config in /etc/network/interfaces
-
-        **ifquery --check br0**
-
-        **ifquery --check --with-depends br0**
-
-        **ifquery --check -a** 
-
-    # dump running state of all interfaces in /etc/network/interfaces format
-
-        **ifquery --running br0**
-
-        **ifquery --running --with-depends br0**
-
-        **ifquery --running -a**
-
-    # print dependency info in list format
-
-        **ifquery --print-dependency=list -a**
-
-        **ifquery --print-dependency=list  br2000**
-
-    # print dependency info in dot format
-
-        **ifquery --print-dependency=dot -a**
-
-        **ifquery --print-dependency=dot br2000**
-
-    # Create an image (png) from the dot format
-
-        **ifquery --print-dependency=dot -a > interfaces.dot**
-
-        **dot -Tpng interfaces.dot > interfaces.png**
-
-        (The above command only works on a system with dot installed)
-
-KNOWN_ISSUES
-============
-    **ifquery --check** is currently experimental
-
-    **ifquery --check** cannot validate usercommands given under pre-up, post-up etc
-    There is currently no support to check/validate ethtool iface attributes
-
-SEE ALSO
-========
-    ifup(8),
-    ifdown(8),
-    ifreload(8),
-    interfaces(5),
-    ifupdown-addons-interfaces(5)
diff --git a/ifupdown2/man.rst/ifreload.8.rst b/ifupdown2/man.rst/ifreload.8.rst
deleted file mode 100644 (file)
index f26442b..0000000
+++ /dev/null
@@ -1,80 +0,0 @@
-========
-ifreload
-========
-
---------------------------------------
-reload network interface configuration
---------------------------------------
-
-:Author: Roopa Prabhu <roopa@cumulusnetworks.com>
-:Date:   2014-02-05
-:Copyright: Copyright 2014 Cumulus Networks, Inc.  All rights reserved.
-:Version: 0.1
-:Manual section: 8
-
-SYNOPSIS
-========
-    ifreload [-h] (-a|-c) [-v] [-d] [-f] [-n] 
-
-DESCRIPTION
-===========
-    reloads network **interfaces(5)** file **/etc/network/interfaces**.
-
-    Runs **ifdown** on interfaces that were removed from the file and
-    subsequently runs **ifup** on all interfaces.
-
-    When removing an interface (iface section) from the interfaces file
-    please make sure all its references are removed as well. Similarly
-    when renaming an interface, please make sure all references to the
-    interface are changed to the new name. Renaming an interface
-    in the interfaces file results in ifdown of the old and ifup
-    of the interface with the new name.
-
-    If you do not wish to execute **down** on any interfaces, but only **up** on
-    interfaces that were already **up**, please see the **--currently-up**
-    option below.
-
-
-OPTIONS
-=======
-    -h, --help            show this help message and exit
-
-    -a, --all             process all interfaces marked "auto"
-
-    -v, --verbose         verbose
-
-    -d, --debug           output debug info
-
-    -f, --force           force run all operations
-
-    -c, --currently-up    only reload auto and other interfaces that are
-                          currently up. This can be used as a non-disruptive
-                          alternative to -a because it will not down any
-                          interfaces
-
-    -X EXCLUDEPATS, --exclude EXCLUDEPATS
-                          Exclude interfaces from the list of interfaces to
-                          operate on. Can be specified multiple times
-
-
-EXAMPLES
-========
-    # reload all auto interfaces in **interfaces(5)** file
-
-    **ifreload -a**
-
-    # reload all interfaces using service command
-
-    **service networking reload**
-
-    # reload all currently up interfaces without bringing any interfaces down
-
-    **service networking reload-currently-up**
-
-SEE ALSO
-========
-    ifup(8),
-    ifdown(8),
-    ifquery(8),
-    interfaces(5),
-    ifupdown-addons-interfaces(5)
diff --git a/ifupdown2/man.rst/ifup.8.rst b/ifupdown2/man.rst/ifup.8.rst
deleted file mode 100644 (file)
index 407b44b..0000000
+++ /dev/null
@@ -1,174 +0,0 @@
-====
-ifup
-====
-
--------------------------------------
-network interface management commands 
--------------------------------------
-
-:Author: Roopa Prabhu <roopa@cumulusnetworks.com>
-:Date:   2014-02-05
-:Copyright: Copyright 2014 Cumulus Networks, Inc.  All rights reserved.
-:Version: 0.1
-:Manual section: 8
-
-NAME
-====
-    **ifup** - bring a network interface up
-
-    **ifdown** - take a network interface down
-
-SYNOPSIS
-========
-
-    ifup [-h] [-a] [-v] [-d] [--allow CLASS] [--with-depends]
-       **[-X EXCLUDEPATS] [-f] [-n] [--print-dependency {list,dot}]**
-       **[IFACE [IFACE ...]]**
-
-    ifdown [-h] [-a] [-v] [-d] [--allow CLASS] [--with-depends]
-           **[-X EXCLUDEPATS] [-f] [-n] [--print-dependency {list,dot}]**
-           **[IFACE [IFACE ...]]**
-
-DESCRIPTION
-===========
-    **ifup** and **ifdown** commands can be used to configure (or, respectively,
-    deconfigure) network interfaces based on interface definitions in the
-    file **/etc/network/interfaces/** file.
-
-    **ifquery(8)** maybe used in conjunction with **ifup** and **ifdown**
-    commands to query and validate applied/running configuration.
-
-    **ifup** always works on the current **interfaces(5)** file under
-    **/etc/network/interfaces**. **ifdown** works on the last applied interface
-    configuration.
-
-    **ifup** on an already ifup'ed interface will re-apply the configuration,
-    skipping already applied configuration whereever possible. In many cases
-    where config commands are idempotent, you will see that ifup/ifdown will
-    reapply the config even if the interface already has that config.
-
-    **ifup** and **ifdown** understands interface dependency order.
-
-    For logical interfaces like vlans, bridges, bonds, **ifup** creates the
-    interface and **ifdown** deletes the interface. Use **--admin-state**
-    option if you only want to administratively bring the interface up/down.
-
-    When **ifup** and **ifdown** are used with interfaces on command line,
-    they must be have a **iface** section in the **interfaces(5)** file.
-
-OPTIONS
-=======
-    positional arguments:
-
-    **IFACE**  interface list separated by spaces. **IFACE** list and **'-a'**
-    argument are mutually exclusive.
-
-    optional arguments:
-
-    -h, --help            show this help message and exit
-
-    -a, --all             process all interfaces marked "auto"
-
-    -v, --verbose         verbose
-
-    -d, --debug           output debug info
-    --allow CLASS         ignore non-"allow-CLASS" interfaces
-
-    -w, --with-depends        run with all dependent interfaces. This option
-                          is redundant when -a is specified. When '-a' is
-                          specified, interfaces are always executed in
-                          dependency order.
-                        
-    -X EXCLUDEPATS, --exclude EXCLUDEPATS
-                          Exclude interfaces from the list of interfaces to
-                          operate on. Can be specified multiple times
-
-    -i INTERFACESFILE, --interfaces INTERFACESFILE
-                          Use interfaces file instead of default
-                          /etc/network/interfaces
-
-    -t {native,json}, --interfaces-format {native,json}
-                          interfaces file format
-
-    -f, --force           force run all operations
-
-    -n, --no-act          print out what would happen, but don't do it
-
-    -p, --print-dependency {list,dot}
-                          print iface dependency in list or dot format
-
-    -m, --admin-state, --no-scripts
-                          dont run any addon modules/scripts. Only bring
-                          the interface administratively up/down
-
-    -u, --use-current-config
-                          By default ifdown looks at the saved state for
-                          interfaces to bring down. This option allows ifdown
-                          to look at the current interfaces file. Useful when
-                          your state file is corrupted or you want down to use
-                          the latest from the interfaces file
-
-EXAMPLES
-========
-    # bringing up all interfaces
-
-        **ifup -a**
-
-    # bringing up interface list
-
-        **ifup swp1 swp2**
-
-    # bringing up interface with its dependents
-
-        **ifup br0 --with-depends**
-
-    # bringing down all interfaces
-
-        **ifdown -a**
-
-    # bringing down a single interface
-
-        **ifdown swp1**
-
-    # excluding interfaces using -X option
-
-        **ifdown -X eth0 -a**
-
-        **ifup -X eth0 -a**
-
-        **ifdown -X eth0 -X lo -a**
-
-    # using verbose -v option to see what is going on
-
-        **ifup -v -a**
-
-    # using debug -d option to see more of what is going on
-
-        **ifup -d -a**
-
-    # ignore errors
-
-        **ifup -a -f**
-
-        **ifdown -a -f**
-
-    # run ifdown and ifup on all interfaces using service command/init script
-
-        **service networking restart**
-
-    # run ifup on all interfaces using service command/init script
-
-        **service networking start**
-
-    # ifdown on all interfaces using service command/init script
-
-        **service networking stop**
-
-    # To run ifup/ifdown on only interfaces that changed see **ifreload(8)**
-
-SEE ALSO
-========
-    ifquery(8),
-    ifreload(8),
-    interfaces(5),
-    ifupdown-addons-interfaces(5)
diff --git a/ifupdown2/man.rst/ifupdown-addons-interfaces.5.rst b/ifupdown2/man.rst/ifupdown-addons-interfaces.5.rst
deleted file mode 100644 (file)
index 94e2f7c..0000000
+++ /dev/null
@@ -1,1373 +0,0 @@
-==========================
-ifupdown-addons-interfaces
-==========================
----------------------------------------------------------
-ifupdown2 addon modules interface configuration
----------------------------------------------------------
-:Author: roopa@cumulusnetworks.com
-:Date:   2013-09-25
-:Copyright: Copyright 2013 Cumulus Networks, Inc.  All rights reserved.
-:Version: 0.1
-:Manual section: 5
-
-
-DESCRIPTION
-===========
-    ifupdown2 addon modules add incremental functionality to
-    core ifupdown2 tool.
-           
-    All installed addon modules are executed on every interface
-    listed in the interfaces file. Addon modules are installed under
-    /usr/share/ifupdownaddons. To see the list of active addon
-    modules, see ifaddon(8).
-
-    Addon modules add new attributes to the interfaces(5) file.
-    Below is a list of attribute options provided by each module.
-    These can be listed under each iface section in the interfaces(5)
-    file.  
-
-
-EXAMPLES
-========
-    Listed below are addon modules and their supported attributes.
-    The attributes if applicable go under the iface section in the
-    interfaces(5) file.
-
-    **ethtool**: ethtool configuration module for interfaces
-
-
-      **link-duplex**
-
-        **help**: set link duplex
-
-
-        **required**: False
-
-        **default**: half
-
-        **validvals**: half,full
-
-        **example**:
-            link-duplex full
-
-
-      **link-autoneg**
-
-        **help**: set autonegotiation
-
-
-        **required**: False
-
-        **default**: off
-
-        **validvals**: on,off
-
-        **example**:
-            link-autoneg on
-
-
-      **link-speed**
-
-        **help**: set link speed
-
-
-        **required**: False
-
-        **example**:
-            link-speed 1000
-
-
-
-    **bridge**: Bridge configuration module. Supports both vlan aware 
-    and non vlan aware bridges. For the vlan aware bridge, the port sp
-    ecific attributes must be specified under the port. And for vlan u
-    naware bridge port specific attributes must be specified under the
-    bridge.
-
-
-      **bridge-vlan-aware**
-
-        **help**: vlan aware bridge. Setting this attribute to yes ena
-        bles vlan filtering on the bridge
-
-
-        **required**: False
-
-        **example**:
-            bridge-vlan-aware yes/no
-
-
-      **bridge-pathcosts**
-
-        **help**: bridge set port path costs
-
-
-        **required**: False
-
-        **default**: 100
-
-        **example**:
-            bridge-pathcosts swp1=100 swp2=100
-
-
-      **bridge-portprios**
-
-        **help**: bridge port prios
-
-
-        **required**: False
-
-        **default**: 32
-
-        **example**:
-            bridge-portprios swp1=32 swp2=32
-
-
-      **bridge-fd**
-
-        **help**: bridge forward delay
-
-
-        **required**: False
-
-        **default**: 15
-
-        **example**:
-            bridge-fd 15
-
-
-      **bridge-ageing**
-
-        **help**: bridge ageing
-
-
-        **required**: False
-
-        **default**: 300
-
-        **example**:
-            bridge-ageing 300
-
-
-      **bridge-hello**
-
-        **help**: bridge set hello time
-
-
-        **required**: False
-
-        **default**: 2
-
-        **example**:
-            bridge-hello 2
-
-
-      **bridge-gcint**
-
-        **help**: bridge garbage collection interval in secs
-
-
-        **required**: False
-
-        **default**: 4
-
-        **example**:
-            bridge-gcint 4
-
-
-      **bridge-mcquerier**
-
-        **help**: set multicast querier
-
-
-        **required**: False
-
-        **default**: 0
-
-        **example**:
-            bridge-mcquerier 0
-
-
-      **bridge-mclmc**
-
-        **help**: set multicast last member count
-
-
-        **required**: False
-
-        **default**: 2
-
-        **example**:
-            bridge-mclmc 2
-
-
-      **bridge-mcsqc**
-
-        **help**: set multicast startup query count
-
-
-        **required**: False
-
-        **default**: 2
-
-        **example**:
-            bridge-mcsqc 2
-
-
-      **bridge-mcrouter**
-
-        **help**: set multicast router
-
-
-        **required**: False
-
-        **default**: 1
-
-        **example**:
-            bridge-mcrouter 1
-
-
-      **bridge-stp**
-
-        **help**: bridge-stp yes/no
-
-
-        **required**: False
-
-        **default**: no
-
-        **validvals**: yes,on,off,no
-
-        **example**:
-            bridge-stp no
-
-
-      **bridge-pvid**
-
-        **help**: bridge port pvid. Must be specified under the bridge
-        port
-
-
-        **required**: False
-
-        **example**:
-            bridge-pvid 1
-
-
-      **bridge-mcsqi**
-
-        **help**: set multicast startup query interval (in secs)
-
-
-        **required**: False
-
-        **default**: 31
-
-        **example**:
-            bridge-mcsqi 31
-
-
-      **bridge-mcmi**
-
-        **help**: set multicast membership interval (in secs)
-
-
-        **required**: False
-
-        **default**: 260
-
-        **example**:
-            bridge-mcmi 260
-
-
-      **bridge-mclmi**
-
-        **help**: set multicast last member interval (in secs)
-
-
-        **required**: False
-
-        **default**: 1
-
-        **example**:
-            bridge-mclmi 1
-
-
-      **bridge-vids**
-
-        **help**: bridge port vids. Can be specified under the bridge 
-        or under the port. If specified under the bridge the ports inh
-        erit it unless overridden by a bridge-vids attribuet under the
-        port
-
-
-        **required**: False
-
-        **example**:
-            bridge-vids 4000
-
-            bridge-vids 2000 2200-3000
-
-
-      **bridge-ports**
-
-        **help**: bridge ports
-
-
-        **required**: True
-
-        **example**:
-            bridge-ports swp1.100 swp2.100 swp3.100
-
-            bridge-ports glob swp1-3.100
-
-            bridge-ports regex (swp[1|2|3].100)
-
-
-      **bridge-mcqifaddr**
-
-        **help**: set multicast query to use ifaddr
-
-
-        **required**: False
-
-        **default**: 0
-
-        **example**:
-            bridge-mcqifaddr 0
-
-
-      **bridge-waitport**
-
-        **help**: wait for a max of time secs for the specified ports 
-        to become available,if no ports are specified then those speci
-        fied on bridge-ports will be used here. Specifying no ports he
-        re should not be used if we are using regex or "all" on bridge
-        _ports,as it wouldnt work.
-
-
-        **required**: False
-
-        **default**: 0
-
-        **example**:
-            bridge-waitport 4 swp1 swp2
-
-
-      **bridge-mcqri**
-
-        **help**: set multicast query response interval (in secs)
-
-
-        **required**: False
-
-        **default**: 10
-
-        **example**:
-            bridge-mcqri 10
-
-
-      **bridge-hashel**
-
-        **help**: set hash elasticity
-
-
-        **required**: False
-
-        **default**: 4096
-
-        **example**:
-            bridge-hashel 4096
-
-
-      **bridge-mcqpi**
-
-        **help**: set multicast querier interval (in secs)
-
-
-        **required**: False
-
-        **default**: 255
-
-        **example**:
-            bridge-mcqpi 255
-
-
-      **bridge-hashmax**
-
-        **help**: set hash max
-
-
-        **required**: False
-
-        **default**: 4096
-
-        **example**:
-            bridge-hashmax 4096
-
-
-      **bridge-bridgeprio**
-
-        **help**: bridge priority
-
-
-        **required**: False
-
-        **default**: 32768
-
-        **example**:
-            bridge-bridgeprio 32768
-
-
-      **bridge-maxage**
-
-        **help**: bridge set maxage
-
-
-        **required**: False
-
-        **default**: 20
-
-        **example**:
-            bridge-maxage 20
-
-
-      **bridge-mcsnoop**
-
-        **help**: set multicast snooping
-
-
-        **required**: False
-
-        **default**: 1
-
-        **example**:
-            bridge-mcsnoop 1
-
-
-      **bridge-access**
-
-        **help**: bridge port access vlan. Must be specified under the
-        bridge port
-
-
-        **required**: False
-
-        **example**:
-            bridge-access 300
-
-
-      **bridge-maxwait**
-
-        **help**: forces to time seconds the maximum time that the Deb
-        ian bridge setup  scripts will wait for the bridge ports to ge
-        t to the forwarding status, doesn't allow factional part. If i
-        t is equal to 0 then no waiting is done
-
-
-        **required**: False
-
-        **default**: 0
-
-        **example**:
-            bridge-maxwait 3
-
-
-      **bridge-portmcrouter**
-
-        **help**: set port multicast routers
-
-
-        **required**: False
-
-        **default**: 1
-
-        **example**:
-            under the bridge: bridge-portmcrouter swp1=1 swp2=1
-
-            under the port: bridge-portmcrouter 1
-
-
-      **bridge-portmcfl**
-
-        **help**: port multicast fast leave.
-
-
-        **required**: False
-
-        **default**: 0
-
-        **example**:
-            under the bridge: bridge-portmcfl swp1=0 swp2=0
-
-            under the port: bridge-portmcfl 0
-
-
-      **bridge-mcqi**
-
-        **help**: set multicast query interval (in secs)
-
-
-        **required**: False
-
-        **default**: 125
-
-        **example**:
-            bridge-mcqi 125
-
-
-
-    **usercmds**: user commands for interfaces
-
-
-      **down**
-
-        **help**: run command at interface down
-
-
-        **required**: False
-
-      **post-up**
-
-        **help**: run command after interface bring up
-
-
-        **required**: False
-
-      **up**
-
-        **help**: run command at interface bring up
-
-
-        **required**: False
-
-      **pre-down**
-
-        **help**: run command before bringing the interface down
-
-
-        **required**: False
-
-      **pre-up**
-
-        **help**: run command before bringing the interface up
-
-
-        **required**: False
-
-      **post-down**
-
-        **help**: run command after bringing interface down
-
-
-        **required**: False
-
-
-    **mstpctl**: mstp configuration module for bridges
-
-
-      **mstpctl-portadminedge**
-
-        **help**: enable/disable initial edge state of the port
-
-
-        **required**: False
-
-        **default**: no
-
-        **validvals**: yes,no
-
-        **example**:
-            mstpctl-portadminedge swp1=no swp2=no
-
-
-      **mstpctl-portbpdufilter**
-
-        **help**: enable/disable bpdu filter on a port. syntax varies 
-        when defined under a bridge vs under a port
-
-
-        **required**: False
-
-        **default**: no
-
-        **validvals**: yes,no
-
-        **example**:
-            under a bridge: mstpctl-portbpdufilter swp1=no swp2=no
-
-            under a port: mstpctl-portbpdufilter yes
-
-
-      **mstpctl-fdelay**
-
-        **help**: set forwarding delay
-
-
-        **required**: False
-
-        **default**: 15
-
-        **example**:
-            mstpctl-fdelay 15
-
-
-      **mstpctl-portnetwork**
-
-        **help**: enable/disable bridge assurance capability for a por
-        t
-
-
-        **required**: False
-
-        **default**: no
-
-        **validvals**: yes,no
-
-        **example**:
-            mstpctl-portnetwork swp1=no swp2=no
-
-
-      **mstpctl-txholdcount**
-
-        **help**: bridge transmit holdcount
-
-
-        **required**: False
-
-        **default**: 6
-
-        **example**:
-            mstpctl-txholdcount 6
-
-
-      **mstpctl-forcevers**
-
-        **help**: bridge force stp version
-
-
-        **required**: False
-
-        **default**: rstp
-
-        **example**:
-            mstpctl-forcevers rstp
-
-
-      **mstpctl-portautoedge**
-
-        **help**: enable/disable auto transition to/from edge state of
-        the port
-
-
-        **required**: False
-
-        **default**: yes
-
-        **validvals**: yes,no
-
-        **example**:
-            mstpctl-portautoedge swp1=yes swp2=yes
-
-
-      **mstpctl-maxhops**
-
-        **help**: bridge max hops
-
-
-        **required**: False
-
-        **default**: 15
-
-        **example**:
-            mstpctl-maxhops 15
-
-
-      **mstpctl-treeprio**
-
-        **help**: tree priority
-
-
-        **required**: False
-
-        **default**: 32768
-
-        validrange: 0-65535
-
-        **example**:
-            mstpctl-treeprio 32768
-
-
-      **mstpctl-treeportprio**
-
-        **help**: port priority for MSTI instance
-
-
-        **required**: False
-
-        **default**: 128
-
-        validrange: 0-240
-
-        **example**:
-            mstpctl-treeportprio swp1=128 swp2=128
-
-
-      **mstpctl-portpathcost**
-
-        **help**: bridge port path cost
-
-
-        **required**: False
-
-        **default**: 0
-
-        **example**:
-            mstpctl-portpathcost swp1=0 swp2=1
-
-
-      **mstpctl-portrestrtcn**
-
-        **help**: enable/disable port ability to propagate received to
-        pology change notification of the port
-
-
-        **required**: False
-
-        **default**: no
-
-        **validvals**: yes,no
-
-        **example**:
-            mstpctl-portrestrtcn swp1=no swp2=no
-
-
-      **mstpctl-maxage**
-
-        **help**: max message age
-
-
-        **required**: False
-
-        **default**: 20
-
-        **example**:
-            mstpctl-maxage 20
-
-
-      **mstpctl-hello**
-
-        **help**: set hello time
-
-
-        **required**: False
-
-        **default**: 2
-
-        **example**:
-            mstpctl-hello 2
-
-
-      **mstpctl-portrestrrole**
-
-        **help**: enable/disable port ability to take root role of the
-        port
-
-
-        **required**: False
-
-        **default**: no
-
-        **validvals**: yes,no
-
-        **example**:
-            mstpctl-portrestrrole swp1=no swp2=no
-
-
-      **mstpctl-bpduguard**
-
-        **help**: enable/disable bpduguard
-
-
-        **required**: False
-
-        **default**: no
-
-        **validvals**: yes,no
-
-        **example**:
-            mstpctl-bpduguard swp1=no swp2=no
-
-
-      **mstpctl-ageing**
-
-        **help**: ageing time
-
-
-        **required**: False
-
-        **default**: 300
-
-        **example**:
-            mstpctl-ageing 300
-
-
-      **mstpctl-treeportcost**
-
-        **help**: port tree cost
-
-
-        **required**: False
-
-      **mstpctl-portp2p**
-
-        **help**: bridge port p2p detection mode
-
-
-        **required**: False
-
-        **default**: auto
-
-        **validvals**: yes,no,auto
-
-        **example**:
-            mstpctl-portp2p swp1=no swp2=no
-
-
-
-    **clagd**: This module generates the clagd defaults file.
-
-
-      **clagd-priority**
-
-        **help**: The priority of this clagd switch
-
-
-        **required**: False
-
-        **example**:
-            clagd-priority 30000
-
-
-      **clagd-backup-ip**
-
-        **help**: Backup IP address of the clagd peer
-
-
-        **required**: False
-
-        **example**:
-            clagd-backup-ip 192.1.1.1
-
-
-      **clagd-enable**
-
-        **help**: enable clagd
-
-
-        **required**: False
-
-        **validvals**: yes,no
-
-        **example**:
-            clagd-enable yes
-
-
-      **clag-id**
-
-        **help**: multi-chassis lag id
-
-
-        **required**: False
-
-        **default**: 0
-
-        validrange: 0-65535
-
-        **example**:
-            clag-id 1
-
-
-      **clagd-peer-ip**
-
-        **help**: The IP address of the clagd peer
-
-
-        **required**: True
-
-        **example**:
-            clagd-peer 10.10.10.2
-
-
-      **clagd-sys-mac**
-
-        **help**: The system ID of the CLAG pair
-
-
-        **required**: True
-
-        **example**:
-            clagd-sys-mac 44:38:39:ff:00:00
-
-
-      **clagd-args**
-
-        **help**: Additional command line arguments for clagd
-
-
-        **required**: False
-
-        **example**:
-            clagd-args --log /var/log/clagd.log
-
-            clagd-args --verbose --lacpPoll 10
-
-            clagd-args --debug 0x4
-
-
-
-    **vlan**: vlan module configures vlan interfaces.This module under
-    stands vlan interfaces with dot notations. eg swp1.100. Vlan inter
-    faces with any other names need to have raw device and vlan id att
-    ributes
-
-
-      **vlan-id**
-
-        **help**: vlan id
-
-
-        **required**: False
-
-      **vlan-raw-device**
-
-        **help**: vlan raw device
-
-
-        **required**: False
-
-
-    **bridgevlan**: bridgevlan module configures vlan attributes on a 
-    vlan aware bridge. This module only understands vlan interface nam
-    e with dot notations. eg br0.100. where br0 is the vlan aware brid
-    ge this config is for
-
-
-      **bridge-igmp-querier-src**
-
-        **help**: bridge igmp querier src. Must be specified under the
-        vlan interface
-
-
-        **required**: False
-
-        **example**:
-            bridge-igmp-querier-src 172.16.101.1
-
-
-
-    **ifenslave**: bond configuration module
-
-
-      **bond-use-carrier**
-
-        **help**: bond use carrier
-
-
-        **required**: False
-
-        **default**: 1
-
-        **validvals**: 0,1
-
-        **example**:
-            bond-use-carrier 1
-
-
-      **bond-lacp-bypass-period**
-
-        **help**: grace period (seconds) for lacp bypass
-
-
-        **required**: False
-
-        **default**: 0
-
-        validrange: 0-900
-
-        **example**:
-            bond-lacp-bypass-period 100
-
-
-      **bond-miimon**
-
-        **help**: bond miimon
-
-
-        **required**: False
-
-        **default**: 0
-
-        validrange: 0-255
-
-        **example**:
-            bond-miimon 0
-
-
-      **bond-lacp-rate**
-
-        **help**: bond lacp rate
-
-
-        **required**: False
-
-        **default**: 0
-
-        **validvals**: 0,1
-
-        **example**:
-            bond-lacp-rate 0
-
-
-      **bond-lacp-bypass-priority**
-
-        **help**: slave priority for lacp bypass
-
-
-        **required**: False
-
-        **example**:
-            bond-lacp-bypass-priority swp1=1 swp2=1 swp3=2
-
-
-      **bond-min-links**
-
-        **help**: bond min links
-
-
-        **required**: False
-
-        **default**: 0
-
-        **example**:
-            bond-min-links 0
-
-
-      **bond-slaves**
-
-        **help**: bond slaves
-
-
-        **required**: True
-
-        **example**:
-            bond-slaves swp1 swp2
-
-            bond-slaves glob swp1-2
-
-            bond-slaves regex (swp[1|2)
-
-
-      **bond-lacp-bypass-allow**
-
-        **help**: allow lacp bypass
-
-
-        **required**: False
-
-        **default**: 0
-
-        **validvals**: 0,1
-
-        **example**:
-            bond-lacp-bypass-allow 0
-
-
-      **bond-mode**
-
-        **help**: bond mode
-
-
-        **required**: False
-
-        **default**: balance-rr
-
-        **validvals**: balance-rr,active-backup,balance-xor,broadcast,802.3ad,balance-tlb,balance-alb
-
-        **example**:
-            bond-mode 802.3ad
-
-
-      **bond-num-unsol-na**
-
-        **help**: bond slave devices
-
-
-        **required**: False
-
-        **default**: 1
-
-        validrange: 0-255
-
-        **example**:
-            bond-num-unsol-na 1
-
-
-      **bond-ad-sys-priority**
-
-        **help**: 802.3ad system priority
-
-
-        **required**: False
-
-        **default**: 65535
-
-        **example**:
-            bond-ad-sys-priority 65535
-
-
-      **bond-xmit-hash-policy**
-
-        **help**: bond slave devices
-
-
-        **required**: False
-
-        **default**: layer2
-
-        **validvals**: layer2,layer3+4,layer2+3
-
-        **example**:
-            bond-xmit-hash-policy layer2
-
-
-      **bond-num-grat-arp**
-
-        **help**: bond use carrier
-
-
-        **required**: False
-
-        **default**: 1
-
-        validrange: 0-255
-
-        **example**:
-            bond-num-grat-arp 1
-
-
-      **bond-ad-sys-mac-addr**
-
-        **help**: 802.3ad system mac address
-
-
-        **required**: False
-
-        **default**: 00:00:00:00:00:00
-
-        **example**:
-            bond-ad-sys-mac-addr 00:00:00:00:00:00
-
-
-
-    **address**: address configuration module for interfaces
-
-
-      **broadcast**
-
-        **help**: broadcast address
-
-
-        **required**: False
-
-        **example**:
-            broadcast 10.0.1.255
-
-
-      **hwaddress**
-
-        **help**: hw address
-
-
-        **required**: False
-
-        **example**:
-            hwaddress 44:38:39:00:27:b8
-
-
-      **alias**
-
-        **help**: description/alias
-
-
-        **required**: False
-
-        **example**:
-            alias testnetwork
-
-
-      **address**
-
-        **help**: ipv4 or ipv6 addresses
-
-
-        **required**: False
-
-        **example**:
-            address 10.0.12.3/24
-
-            address 2000:1000:1000:1000:3::5/128
-
-
-      **scope**
-
-        **help**: scope
-
-
-        **required**: False
-
-        **example**:
-            scope host
-
-
-      **address-purge**
-
-        **help**: purge existing addresses. By default any existing ip
-        addresses on an interface are purged to match persistant addre
-        sses in the interfaces file. Set this attribute to 'no'if you 
-        want to preserve existing addresses
-
-
-        **required**: False
-
-        **default**: yes
-
-        **example**:
-            address-purge yes/no
-
-
-      **preferred-lifetime**
-
-        **help**: preferred lifetime
-
-
-        **required**: False
-
-        **example**:
-            preferred-lifetime forever
-
-            preferred-lifetime 10
-
-
-      **gateway**
-
-        **help**: default gateway
-
-
-        **required**: False
-
-        **example**:
-            gateway 255.255.255.0
-
-
-      **mtu**
-
-        **help**: interface mtu
-
-
-        **required**: False
-
-        **default**: 1500
-
-        **example**:
-            mtu 1600
-
-
-
-    **addressvirtual**: address module configures virtual addresses fo
-    r interfaces. It creates a macvlan interface for every mac ip addr
-    ess-virtual line
-
-
-      **address-virtual**
-
-        **help**: bridge router virtual mac and ip
-
-
-        **required**: False
-
-        **example**:
-            address-virtual 00:11:22:33:44:01 11.0.1.254/24 11.0.1.254/24
-
-
-
-    **vxlan**: vxlan module configures vxlan interfaces.
-
-
-      **vxlan-learning**
-
-        **help**: vxlan learning on/off
-
-
-        **required**: False
-
-        **default**: on
-
-        **example**:
-            vxlan-learning off
-
-
-      **vxlan-id**
-
-        **help**: vxlan id
-
-
-        **required**: True
-
-        **example**:
-            vxlan-id 100
-
-
-      **vxlan-remoteip**
-
-        **help**: vxlan remote ip
-
-
-        **required**: False
-
-        **example**:
-            vxlan-remoteip 172.16.22.127
-
-
-      **vxlan-svcnodeip**
-
-        **help**: vxlan id
-
-
-        **required**: False
-
-        **example**:
-            vxlan-svcnodeip 172.16.22.125
-
-
-      **vxlan-local-tunnelip**
-
-        **help**: vxlan local tunnel ip
-
-
-        **required**: False
-
-        **example**:
-            vxlan-local-tunnelip 172.16.20.103
-
-
-
-SEE ALSO
-========
-    interfaces(5),
-    ifup(8),
-    ip(8),
-    mstpctl(8),
-    brctl(8),
-    ethtool(8),
-    clagctl(8)
diff --git a/ifupdown2/man.rst/interfaces.5.rst b/ifupdown2/man.rst/interfaces.5.rst
deleted file mode 100644 (file)
index e77e1c9..0000000
+++ /dev/null
@@ -1,155 +0,0 @@
-==========
-interfaces
-==========
-
---------------------------------------------
-network interface configuration for ifupdown
---------------------------------------------
-
-:Author: Roopa Prabhu <roopa@cumulusnetworks.com>
-:Date:   2014-02-05
-:Copyright: Copyright 2014 Cumulus Networks, Inc.  All rights reserved.
-:Version: 0.1
-:Manual section: 5 
-
-DESCRIPTION
-===========
-    **/etc/network/interfaces** contains network interface configuration
-    information for the **ifup(8)**, **ifdown(8)** and **ifquery(8)** commands.
-
-    This is where you configure how your system is connected to the network.
-
-    Lines starting with # are ignored. Note that end-of-line comments are
-    NOT supported, comments must be on a line of their own.
-
-    A line may be extended across multiple lines by making the last character
-    a backslash.
-
-    The file consists of zero or more "iface", "auto",  "allow-"
-    and "source" stanzas. Here is an example::
-
-        auto lo eth0
-        allow-hotplug eth1
-
-        iface lo inet loopback
-
-        source /etc/network/interfaces.d/bridges
-
-        iface eth0 inet static
-            address 192.168.1.1/24
-            up flush-mail
-
-        iface eth1 inet dhcp
-
-    Lines beginning with the word "auto" are used to identify the physical
-    interfaces to be brought up when ifup is run with the -a option.
-    (This option is used by the system boot scripts.) Physical interface names
-    should follow the word "auto" on the same line.  There can be  multiple
-    "auto"  stanzas.
-
-    Lines beginning with "allow-" are  used  to  identify  interfaces  that
-    should  be  brought  up automatically by various subsytems. This may be
-    done using a command such as "ifup --allow=hotplug  eth0  eth1",  which
-    will  only  bring up eth0 or eth1 if it is listed in an "allow-hotplug"
-    line. Note that "allow-auto" and "auto" are synonyms.
-
-    Lines beginning with "source" are used to include  stanzas  from  other
-    files, so configuration can be split into many files. The word "source"
-    is followed by the path of file to be sourced. Shell wildcards  can  be
-    used. Currently only supports absolute
-    path names.
-
-    iface is normally given a interface name as its first non-option
-    argument. 
-
-    The interface name is followed by the name of the address family that the
-    interface uses. This will be "inet" for TCP/IP networking and inet6 for
-    ipv6. Following that is the name of the method used to configure the
-    interface.
-
-    ifupdown supports iface stanzas without a family or a method. This enables
-    using the same stanza for inet and inet6 family addresses. And the method
-    defaults to "static"
-
-    Additional interface options/attributes can be given on subsequent lines
-    in the iface stanza. These options come from addon modules. see
-    **ifupdown-addons-interfaces(5)** for these options.
-
-    example bridge interface with additional attributes listed in the
-    **ifupdown-addons-interfaces(5)** man page::
-
-        auto br0
-        iface br0
-            address 12.0.0.4/24
-            address 2000:1000:1000:1000:3::5/128
-            bridge-ports swp1 swp2 swp3
-            bridge-stp on
-
-    ifupdown supports python-mako style templates in the interfaces file.
-    See examples section for details.
-
-    See **/usr/share/doc/python-ifupdown2/examples/** for **interfaces(5)**
-    file examples and interfaces file generation scripts.
-
-METHODS
-=======
-    Both **inet** and **inet6** address family interfaces can use the following
-    methods (However they are not required):
-
-    The loopback Method
-           This method may be used to define the loopback interface.
-
-    The static Method
-           This method may be used to define ethernet interfaces with
-           statically allocated addresses.
-
-    The dhcp Method
-           This method may be used to obtain an address via DHCP.
-
-BUILTIN INTERFACES
-==================
-    **iface** sections for some interfaces like physical interfaces or vlan
-    interfaces in dot notation (like eth1.100) are understood by ifupdown.
-    These interfaces do not need an entry in the interfaces file if
-    they are dependents of other interfaces and dont need any specific
-    configurations like addresses etc.
-
-EXAMPLES
-========
-    Sample /etc/network/interfaces file::
-
-        auto lo
-        iface lo
-            address 192.168.2.0/24
-            address 2001:dee:eeee:1::4/128
-
-        auto eth0
-        iface eth0 inet dhcp
-
-        auto eth1
-        iface eth1 inet manual
-            address 192.168.2.0/24
-            address 2001:dee:eeee:1::4/128
-
-        # source files from a directory /etc/network/interfaces.d
-        source /etc/network/interfaces.d/*
-
-        # Using mako style templates
-        % for v in [11,12]:
-            auto vlan${v}
-            iface vlan${v} inet static
-                address 10.20.${v}.3/24
-        % endfor
-
-    For additional syntax and examples see **ifupdown-addons-interfaces(5)**
-
-FILES
-=====
-    /etc/network/interfaces
-
-SEE ALSO
-========
-    ifupdown-addons-interfaces(5),
-    ifup(8),
-    ifquery(8),
-    ifreload(8)
diff --git a/ifupdown2/man/ifquery.8 b/ifupdown2/man/ifquery.8
deleted file mode 100644 (file)
index 65e89e2..0000000
+++ /dev/null
@@ -1,230 +0,0 @@
-.\" Man page generated from reStructeredText.
-.
-.TH IFQUERY 8 "2014-02-05" "0.1" ""
-.SH NAME
-ifquery \- query network interface configuration
-.
-.nr rst2man-indent-level 0
-.
-.de1 rstReportMargin
-\\$1 \\n[an-margin]
-level \\n[rst2man-indent-level]
-level margin: \\n[rst2man-indent\\n[rst2man-indent-level]]
--
-\\n[rst2man-indent0]
-\\n[rst2man-indent1]
-\\n[rst2man-indent2]
-..
-.de1 INDENT
-.\" .rstReportMargin pre:
-. RS \\$1
-. nr rst2man-indent\\n[rst2man-indent-level] \\n[an-margin]
-. nr rst2man-indent-level +1
-.\" .rstReportMargin post:
-..
-.de UNINDENT
-. RE
-.\" indent \\n[an-margin]
-.\" old: \\n[rst2man-indent\\n[rst2man-indent-level]]
-.nr rst2man-indent-level -1
-.\" new: \\n[rst2man-indent\\n[rst2man-indent-level]]
-.in \\n[rst2man-indent\\n[rst2man-indent-level]]u
-..
-.SH SYNOPSIS
-.INDENT 0.0
-.INDENT 3.5
-\fBifquery [\-v] [\-\-allow CLASS] [\-\-with\-depends] \-a|IFACE...\fP
-.sp
-\fBifquery [\-v] [\-r|\-\-running] [\-\-allow CLASS] [\-\-with\-depends] \-a|IFACE...\fP
-.sp
-\fBifquery [\-v] [\-c|\-\-check] [\-\-allow CLASS] [\-\-with\-depends] \-a|IFACE...\fP
-.sp
-\fBifquery [\-v] [\-p|\-\-print\-dependency {list,dot}] [\-\-allow CLASS] [\-\-with\-depends] \-a|IFACE...\fP
-.sp
-\fBifquery [\-v] \-s|\-\-syntax\-help\fP
-.UNINDENT
-.UNINDENT
-.SH DESCRIPTION
-.INDENT 0.0
-.INDENT 3.5
-\fBifquery\fP can be used to parse interface configuration file, query
-running state or check running state of the interface with configuration
-in \fB/etc/network/interfaces\fP file.
-.sp
-\fBifquery\fP always works on the current \fBinterfaces(5)\fP file
-\fB/etc/network/interfaces\fP unless an alternate interfaces file is
-provided with the \fB\-i\fP option.
-.UNINDENT
-.UNINDENT
-.SH OPTIONS
-.INDENT 0.0
-.INDENT 3.5
-positional arguments:
-.sp
-\fBIFACE\fP   interface list separated by spaces. \fBIFACE\fP list and \fB\(aq\-a\(aq\fP argument are mutually exclusive.
-.sp
-optional arguments:
-.INDENT 0.0
-.TP
-.B \-h,  \-\-help
-show this help message and exit
-.TP
-.B \-a,  \-\-all
-process all interfaces marked "auto"
-.TP
-.B \-v,  \-\-verbose
-verbose
-.TP
-.B \-d,  \-\-debug
-output debug info
-.TP
-.BI \-\-allow \ CLASS
-ignore non\-"allow\-CLASS" interfaces
-.TP
-.B \-w,  \-\-with\-depends
-run with all dependent interfaces. This option
-is redundant when \-a is specified. When \(aq\-a\(aq is
-specified, interfaces are always executed in
-dependency order.
-.TP
-.BI \-X \ EXCLUDEPATS, \ \-\-exclude \ EXCLUDEPATS
-Exclude interfaces from the list of interfaces to
-operate on. Can be specified multiple times
-.TP
-.BI \-i \ INTERFACESFILE, \ \-\-interfaces \ INTERFACESFILE
-Use interfaces file instead of default
-/etc/network/interfaces
-.UNINDENT
-.INDENT 0.0
-.TP
-.B \-t {native,json}, \-\-interfaces\-format {native,json}
-interfaces file format
-.UNINDENT
-.INDENT 0.0
-.TP
-.B \-r,  \-\-running
-print raw interfaces file entries
-.TP
-.B \-c,  \-\-check
-check interface file contents against running state
-of an interface. Returns exit code 0 on success and
-1 on error
-.TP
-.B \-x,  \-\-raw
-print raw config file entries
-.UNINDENT
-.INDENT 0.0
-.TP
-.B \-o {native,json}, \-\-format {native,json}
-interface display format
-.TP
-.B \-p, \-\-print\-dependency {list,dot}
-print iface dependency in list or dot format
-.UNINDENT
-.INDENT 0.0
-.TP
-.B \-s,  \-\-syntax\-help
-print supported interface config syntax. Scans all
-addon modules and dumps supported syntax from them
-if provided by the module.
-.UNINDENT
-.UNINDENT
-.UNINDENT
-.SH EXAMPLES
-.INDENT 0.0
-.INDENT 3.5
-# dump all or some interfaces config file entries
-# (pretty prints user provided entries)
-.INDENT 0.0
-.INDENT 3.5
-\fBifquery \-a\fP
-.sp
-\fBifquery br0\fP
-.UNINDENT
-.UNINDENT
-.sp
-# Same as above but dump with dependencies
-.INDENT 0.0
-.INDENT 3.5
-\fBifquery br0 \-\-with\-depends\fP
-.UNINDENT
-.UNINDENT
-.sp
-# Check running state with the config in /etc/network/interfaces
-.INDENT 0.0
-.INDENT 3.5
-\fBifquery \-\-check br0\fP
-.sp
-\fBifquery \-\-check \-\-with\-depends br0\fP
-.sp
-\fBifquery \-\-check \-a\fP
-.UNINDENT
-.UNINDENT
-.sp
-# dump running state of all interfaces in /etc/network/interfaces format
-.INDENT 0.0
-.INDENT 3.5
-\fBifquery \-\-running br0\fP
-.sp
-\fBifquery \-\-running \-\-with\-depends br0\fP
-.sp
-\fBifquery \-\-running \-a\fP
-.UNINDENT
-.UNINDENT
-.sp
-# print dependency info in list format
-.INDENT 0.0
-.INDENT 3.5
-\fBifquery \-\-print\-dependency=list \-a\fP
-.sp
-\fBifquery \-\-print\-dependency=list  br2000\fP
-.UNINDENT
-.UNINDENT
-.sp
-# print dependency info in dot format
-.INDENT 0.0
-.INDENT 3.5
-\fBifquery \-\-print\-dependency=dot \-a\fP
-.sp
-\fBifquery \-\-print\-dependency=dot br2000\fP
-.UNINDENT
-.UNINDENT
-.sp
-# Create an image (png) from the dot format
-.INDENT 0.0
-.INDENT 3.5
-\fBifquery \-\-print\-dependency=dot \-a > interfaces.dot\fP
-.sp
-\fBdot \-Tpng interfaces.dot > interfaces.png\fP
-.sp
-(The above command only works on a system with dot installed)
-.UNINDENT
-.UNINDENT
-.UNINDENT
-.UNINDENT
-.SH KNOWN_ISSUES
-.INDENT 0.0
-.INDENT 3.5
-\fBifquery \-\-check\fP is currently experimental
-.sp
-\fBifquery \-\-check\fP cannot validate usercommands given under pre\-up, post\-up etc
-There is currently no support to check/validate ethtool iface attributes
-.UNINDENT
-.UNINDENT
-.SH SEE ALSO
-.INDENT 0.0
-.INDENT 3.5
-ifup(8),
-ifdown(8),
-ifreload(8),
-interfaces(5),
-ifupdown\-addons\-interfaces(5)
-.UNINDENT
-.UNINDENT
-.SH AUTHOR
-Roopa Prabhu <roopa@cumulusnetworks.com>
-.SH COPYRIGHT
-Copyright 2014 Cumulus Networks, Inc.  All rights reserved.
-.\" Generated by docutils manpage writer.
-.\" 
-.
diff --git a/ifupdown2/man/ifreload.8 b/ifupdown2/man/ifreload.8
deleted file mode 100644 (file)
index a39da36..0000000
+++ /dev/null
@@ -1,116 +0,0 @@
-.\" Man page generated from reStructeredText.
-.
-.TH IFRELOAD 8 "2014-02-05" "0.1" ""
-.SH NAME
-ifreload \- reload network interface configuration
-.
-.nr rst2man-indent-level 0
-.
-.de1 rstReportMargin
-\\$1 \\n[an-margin]
-level \\n[rst2man-indent-level]
-level margin: \\n[rst2man-indent\\n[rst2man-indent-level]]
--
-\\n[rst2man-indent0]
-\\n[rst2man-indent1]
-\\n[rst2man-indent2]
-..
-.de1 INDENT
-.\" .rstReportMargin pre:
-. RS \\$1
-. nr rst2man-indent\\n[rst2man-indent-level] \\n[an-margin]
-. nr rst2man-indent-level +1
-.\" .rstReportMargin post:
-..
-.de UNINDENT
-. RE
-.\" indent \\n[an-margin]
-.\" old: \\n[rst2man-indent\\n[rst2man-indent-level]]
-.nr rst2man-indent-level -1
-.\" new: \\n[rst2man-indent\\n[rst2man-indent-level]]
-.in \\n[rst2man-indent\\n[rst2man-indent-level]]u
-..
-.SH SYNOPSIS
-.INDENT 0.0
-.INDENT 3.5
-ifreload [\-h] (\-a|\-c) [\-v] [\-d] [\-f] [\-n]
-.UNINDENT
-.UNINDENT
-.SH DESCRIPTION
-.INDENT 0.0
-.INDENT 3.5
-reloads network \fBinterfaces(5)\fP file \fB/etc/network/interfaces\fP.
-.sp
-Runs \fBifdown\fP on interfaces that changed in the interfaces file and
-subsequently runs \fBifup\fP on all interfaces.
-.sp
-\fBifreload\fP is equivalent to \fBifdown \-a\fP followed by \fBifup \-a\fP
-but it skips \fBifdown\fP for interfaces that did not change in the config
-file.
-.sp
-If you do not wish to execute \fBdown\fP on any interfaces, but only \fBup\fP on
-interfaces that were already \fBup\fP, please see the \fB\-\-currently\-up\fP
-option below.
-.UNINDENT
-.UNINDENT
-.SH OPTIONS
-.INDENT 0.0
-.INDENT 3.5
-.INDENT 0.0
-.TP
-.B \-h,  \-\-help
-show this help message and exit
-.TP
-.B \-a,  \-\-all
-process all interfaces marked "auto"
-.TP
-.B \-v,  \-\-verbose
-verbose
-.TP
-.B \-d,  \-\-debug
-output debug info
-.TP
-.B \-f,  \-\-force
-force run all operations
-.TP
-.B \-c,  \-\-currently\-up
-only reload auto and other interfaces that are
-currently up. This can be used as a non\-disruptive
-alternative to \-a because it will not down any
-interfaces
-.UNINDENT
-.UNINDENT
-.UNINDENT
-.SH EXAMPLES
-.INDENT 0.0
-.INDENT 3.5
-# reload all auto interfaces in \fBinterfaces(5)\fP file
-.sp
-\fBifreload \-a\fP
-.sp
-# reload all interfaces using service command
-.sp
-\fBservice networking reload\fP
-.sp
-# reload all currently up interfaces without bringing any interfaces down
-.sp
-\fBservice networking reload\-currently\-up\fP
-.UNINDENT
-.UNINDENT
-.SH SEE ALSO
-.INDENT 0.0
-.INDENT 3.5
-ifup(8),
-ifdown(8),
-ifquery(8),
-interfaces(5),
-ifupdown\-addons\-interfaces(5)
-.UNINDENT
-.UNINDENT
-.SH AUTHOR
-Roopa Prabhu <roopa@cumulusnetworks.com>
-.SH COPYRIGHT
-Copyright 2014 Cumulus Networks, Inc.  All rights reserved.
-.\" Generated by docutils manpage writer.
-.\" 
-.
diff --git a/ifupdown2/man/ifup.8 b/ifupdown2/man/ifup.8
deleted file mode 100644 (file)
index ae72d9f..0000000
+++ /dev/null
@@ -1,269 +0,0 @@
-.\" Man page generated from reStructeredText.
-.
-.TH IFUP 8 "2014-02-05" "0.1" ""
-.SH NAME
-ifup \- network interface management commands
-.
-.nr rst2man-indent-level 0
-.
-.de1 rstReportMargin
-\\$1 \\n[an-margin]
-level \\n[rst2man-indent-level]
-level margin: \\n[rst2man-indent\\n[rst2man-indent-level]]
--
-\\n[rst2man-indent0]
-\\n[rst2man-indent1]
-\\n[rst2man-indent2]
-..
-.de1 INDENT
-.\" .rstReportMargin pre:
-. RS \\$1
-. nr rst2man-indent\\n[rst2man-indent-level] \\n[an-margin]
-. nr rst2man-indent-level +1
-.\" .rstReportMargin post:
-..
-.de UNINDENT
-. RE
-.\" indent \\n[an-margin]
-.\" old: \\n[rst2man-indent\\n[rst2man-indent-level]]
-.nr rst2man-indent-level -1
-.\" new: \\n[rst2man-indent\\n[rst2man-indent-level]]
-.in \\n[rst2man-indent\\n[rst2man-indent-level]]u
-..
-.SH NAME
-.INDENT 0.0
-.INDENT 3.5
-\fBifup\fP \- bring a network interface up
-.sp
-\fBifdown\fP \- take a network interface down
-.UNINDENT
-.UNINDENT
-.SH SYNOPSIS
-.INDENT 0.0
-.INDENT 3.5
-.INDENT 0.0
-.TP
-.B ifup [\-h] [\-a] [\-v] [\-d] [\-\-allow CLASS] [\-\-with\-depends]
-\fB[\-X EXCLUDEPATS] [\-f] [\-n] [\-\-print\-dependency {list,dot}]\fP
-\fB[IFACE [IFACE ...]]\fP
-.TP
-.B ifdown [\-h] [\-a] [\-v] [\-d] [\-\-allow CLASS] [\-\-with\-depends]
-\fB[\-X EXCLUDEPATS] [\-f] [\-n] [\-\-print\-dependency {list,dot}]\fP
-\fB[IFACE [IFACE ...]]\fP
-.UNINDENT
-.UNINDENT
-.UNINDENT
-.SH DESCRIPTION
-.INDENT 0.0
-.INDENT 3.5
-\fBifup\fP and \fBifdown\fP commands can be used to configure (or, respectively,
-deconfigure) network interfaces based on interface definitions in the
-file \fB/etc/network/interfaces/\fP file.
-.sp
-\fBifquery(8)\fP maybe used in conjunction with \fBifup\fP and \fBifdown\fP
-commands to query and validate applied/running configuration.
-.sp
-\fBifup\fP always works on the current \fBinterfaces(5)\fP file under
-\fB/etc/network/interfaces\fP. \fBifdown\fP works on the last applied interface
-configuration.
-.sp
-\fBifup\fP on an already ifup\(aqed interface will re\-apply the configuration,
-skipping already applied configuration whereever possible. In many cases
-where config commands are idempotent, you will see that ifup/ifdown will
-reapply the config even if the interface already has that config.
-.sp
-\fBifup\fP and \fBifdown\fP understands interface dependency order.
-.sp
-For logical interfaces like vlans, bridges, bonds, \fBifup\fP creates the
-interface and \fBifdown\fP deletes the interface. Use \fB\-\-admin\-state\fP
-option if you only want to administratively bring the interface up/down.
-.sp
-When \fBifup\fP and \fBifdown\fP are used with interfaces on command line,
-they must be have a \fBiface\fP section in the \fBinterfaces(5)\fP file.
-.UNINDENT
-.UNINDENT
-.SH OPTIONS
-.INDENT 0.0
-.INDENT 3.5
-positional arguments:
-.sp
-\fBIFACE\fP  interface list separated by spaces. \fBIFACE\fP list and \fB\(aq\-a\(aq\fP
-argument are mutually exclusive.
-.sp
-optional arguments:
-.INDENT 0.0
-.TP
-.B \-h,  \-\-help
-show this help message and exit
-.TP
-.B \-a,  \-\-all
-process all interfaces marked "auto"
-.TP
-.B \-v,  \-\-verbose
-verbose
-.TP
-.B \-d,  \-\-debug
-output debug info
-.TP
-.BI \-\-allow \ CLASS
-ignore non\-"allow\-CLASS" interfaces
-.TP
-.B \-w,  \-\-with\-depends
-run with all dependent interfaces. This option
-is redundant when \-a is specified. When \(aq\-a\(aq is
-specified, interfaces are always executed in
-dependency order.
-.TP
-.BI \-X \ EXCLUDEPATS, \ \-\-exclude \ EXCLUDEPATS
-Exclude interfaces from the list of interfaces to
-operate on. Can be specified multiple times
-.TP
-.BI \-i \ INTERFACESFILE, \ \-\-interfaces \ INTERFACESFILE
-Use interfaces file instead of default
-/etc/network/interfaces
-.UNINDENT
-.INDENT 0.0
-.TP
-.B \-t {native,json}, \-\-interfaces\-format {native,json}
-interfaces file format
-.UNINDENT
-.INDENT 0.0
-.TP
-.B \-f,  \-\-force
-force run all operations
-.TP
-.B \-n,  \-\-no\-act
-print out what would happen, but don\(aqt do it
-.UNINDENT
-.INDENT 0.0
-.TP
-.B \-p, \-\-print\-dependency {list,dot}
-print iface dependency in list or dot format
-.UNINDENT
-.INDENT 0.0
-.TP
-.B \-m,  \-\-admin\-state,  \-\-no\-scripts
-dont run any addon modules/scripts. Only bring
-the interface administratively up/down
-.TP
-.B \-u,  \-\-use\-current\-config
-By default ifdown looks at the saved state for
-interfaces to bring down. This option allows ifdown
-to look at the current interfaces file. Useful when
-your state file is corrupted or you want down to use
-the latest from the interfaces file
-.UNINDENT
-.UNINDENT
-.UNINDENT
-.SH EXAMPLES
-.INDENT 0.0
-.INDENT 3.5
-# bringing up all interfaces
-.INDENT 0.0
-.INDENT 3.5
-\fBifup \-a\fP
-.UNINDENT
-.UNINDENT
-.sp
-# bringing up interface list
-.INDENT 0.0
-.INDENT 3.5
-\fBifup swp1 swp2\fP
-.UNINDENT
-.UNINDENT
-.sp
-# bringing up interface with its dependents
-.INDENT 0.0
-.INDENT 3.5
-\fBifup br0 \-\-with\-depends\fP
-.UNINDENT
-.UNINDENT
-.sp
-# bringing down all interfaces
-.INDENT 0.0
-.INDENT 3.5
-\fBifdown \-a\fP
-.UNINDENT
-.UNINDENT
-.sp
-# bringing down a single interface
-.INDENT 0.0
-.INDENT 3.5
-\fBifdown swp1\fP
-.UNINDENT
-.UNINDENT
-.sp
-# excluding interfaces using \-X option
-.INDENT 0.0
-.INDENT 3.5
-\fBifdown \-X eth0 \-a\fP
-.sp
-\fBifup \-X eth0 \-a\fP
-.sp
-\fBifdown \-X eth0 \-X lo \-a\fP
-.UNINDENT
-.UNINDENT
-.sp
-# using verbose \-v option to see what is going on
-.INDENT 0.0
-.INDENT 3.5
-\fBifup \-v \-a\fP
-.UNINDENT
-.UNINDENT
-.sp
-# using debug \-d option to see more of what is going on
-.INDENT 0.0
-.INDENT 3.5
-\fBifup \-d \-a\fP
-.UNINDENT
-.UNINDENT
-.sp
-# ignore errors
-.INDENT 0.0
-.INDENT 3.5
-\fBifup \-a \-f\fP
-.sp
-\fBifdown \-a \-f\fP
-.UNINDENT
-.UNINDENT
-.sp
-# run ifdown and ifup on all interfaces using service command/init script
-.INDENT 0.0
-.INDENT 3.5
-\fBservice networking restart\fP
-.UNINDENT
-.UNINDENT
-.sp
-# run ifup on all interfaces using service command/init script
-.INDENT 0.0
-.INDENT 3.5
-\fBservice networking start\fP
-.UNINDENT
-.UNINDENT
-.sp
-# ifdown on all interfaces using service command/init script
-.INDENT 0.0
-.INDENT 3.5
-\fBservice networking stop\fP
-.UNINDENT
-.UNINDENT
-.sp
-# To run ifup/ifdown on only interfaces that changed see \fBifreload(8)\fP
-.UNINDENT
-.UNINDENT
-.SH SEE ALSO
-.INDENT 0.0
-.INDENT 3.5
-ifquery(8),
-ifreload(8),
-interfaces(5),
-ifupdown\-addons\-interfaces(5)
-.UNINDENT
-.UNINDENT
-.SH AUTHOR
-Roopa Prabhu <roopa@cumulusnetworks.com>
-.SH COPYRIGHT
-Copyright 2014 Cumulus Networks, Inc.  All rights reserved.
-.\" Generated by docutils manpage writer.
-.\" 
-.
diff --git a/ifupdown2/man/ifupdown-addons-interfaces.5 b/ifupdown2/man/ifupdown-addons-interfaces.5
deleted file mode 100644 (file)
index 86d71a7..0000000
+++ /dev/null
@@ -1,1343 +0,0 @@
-.\" Man page generated from reStructeredText.
-.
-.TH IFUPDOWN-ADDONS-INTERFACES 5 "2013-09-25" "0.1" ""
-.SH NAME
-ifupdown-addons-interfaces \- ifupdown2 addon modules interface configuration
-.
-.nr rst2man-indent-level 0
-.
-.de1 rstReportMargin
-\\$1 \\n[an-margin]
-level \\n[rst2man-indent-level]
-level margin: \\n[rst2man-indent\\n[rst2man-indent-level]]
--
-\\n[rst2man-indent0]
-\\n[rst2man-indent1]
-\\n[rst2man-indent2]
-..
-.de1 INDENT
-.\" .rstReportMargin pre:
-. RS \\$1
-. nr rst2man-indent\\n[rst2man-indent-level] \\n[an-margin]
-. nr rst2man-indent-level +1
-.\" .rstReportMargin post:
-..
-.de UNINDENT
-. RE
-.\" indent \\n[an-margin]
-.\" old: \\n[rst2man-indent\\n[rst2man-indent-level]]
-.nr rst2man-indent-level -1
-.\" new: \\n[rst2man-indent\\n[rst2man-indent-level]]
-.in \\n[rst2man-indent\\n[rst2man-indent-level]]u
-..
-.SH DESCRIPTION
-.INDENT 0.0
-.INDENT 3.5
-ifupdown2 addon modules add incremental functionality to
-core ifupdown2 tool.
-.sp
-All installed addon modules are executed on every interface
-listed in the interfaces file. Addon modules are installed under
-/usr/share/ifupdownaddons. To see the list of active addon
-modules, see ifaddon(8).
-.sp
-Addon modules add new attributes to the interfaces(5) file.
-Below is a list of attribute options provided by each module.
-These can be listed under each iface section in the interfaces(5)
-file.
-.UNINDENT
-.UNINDENT
-.SH EXAMPLES
-.INDENT 0.0
-.INDENT 3.5
-Listed below are addon modules and their supported attributes.
-The attributes if applicable go under the iface section in the
-interfaces(5) file.
-.sp
-\fBethtool\fP: ethtool configuration module for interfaces
-.INDENT 0.0
-.INDENT 3.5
-\fBlink\-duplex\fP
-.INDENT 0.0
-.INDENT 3.5
-\fBhelp\fP: set link duplex
-.sp
-\fBrequired\fP: False
-.sp
-\fBdefault\fP: half
-.sp
-\fBvalidvals\fP: half,full
-.INDENT 0.0
-.TP
-.B \fBexample\fP:
-link\-duplex full
-.UNINDENT
-.UNINDENT
-.UNINDENT
-.sp
-\fBlink\-autoneg\fP
-.INDENT 0.0
-.INDENT 3.5
-\fBhelp\fP: set autonegotiation
-.sp
-\fBrequired\fP: False
-.sp
-\fBdefault\fP: off
-.sp
-\fBvalidvals\fP: on,off
-.INDENT 0.0
-.TP
-.B \fBexample\fP:
-link\-autoneg on
-.UNINDENT
-.UNINDENT
-.UNINDENT
-.sp
-\fBlink\-speed\fP
-.INDENT 0.0
-.INDENT 3.5
-\fBhelp\fP: set link speed
-.sp
-\fBrequired\fP: False
-.INDENT 0.0
-.TP
-.B \fBexample\fP:
-link\-speed 1000
-.UNINDENT
-.UNINDENT
-.UNINDENT
-.UNINDENT
-.UNINDENT
-.sp
-\fBbridge\fP: bridge configuration module
-.INDENT 0.0
-.INDENT 3.5
-\fBbridge\-mcqifaddr\fP
-.INDENT 0.0
-.INDENT 3.5
-\fBhelp\fP: set multicast query to use ifaddr
-.sp
-\fBrequired\fP: False
-.sp
-\fBdefault\fP: 0
-.INDENT 0.0
-.TP
-.B \fBexample\fP:
-bridge\-mcqifaddr 0
-.UNINDENT
-.UNINDENT
-.UNINDENT
-.sp
-\fBbridge\-gcint\fP
-.INDENT 0.0
-.INDENT 3.5
-\fBhelp\fP: bridge garbage collection interval in secs
-.sp
-\fBrequired\fP: False
-.sp
-\fBdefault\fP: 4
-.INDENT 0.0
-.TP
-.B \fBexample\fP:
-bridge\-gcint 4
-.UNINDENT
-.UNINDENT
-.UNINDENT
-.sp
-\fBbridge\-mcsqc\fP
-.INDENT 0.0
-.INDENT 3.5
-\fBhelp\fP: set multicast startup query count
-.sp
-\fBrequired\fP: False
-.sp
-\fBdefault\fP: 2
-.INDENT 0.0
-.TP
-.B \fBexample\fP:
-bridge\-mcsqc 2
-.UNINDENT
-.UNINDENT
-.UNINDENT
-.sp
-\fBbridge\-stp\fP
-.INDENT 0.0
-.INDENT 3.5
-\fBhelp\fP: bridge\-stp yes/no
-.sp
-\fBrequired\fP: False
-.sp
-\fBdefault\fP: no
-.sp
-\fBvalidvals\fP: yes,on,off,no
-.INDENT 0.0
-.TP
-.B \fBexample\fP:
-bridge\-stp no
-.UNINDENT
-.UNINDENT
-.UNINDENT
-.sp
-\fBbridge\-mcsqi\fP
-.INDENT 0.0
-.INDENT 3.5
-\fBhelp\fP: set multicast startup query interval (in secs)
-.sp
-\fBrequired\fP: False
-.sp
-\fBdefault\fP: 31
-.INDENT 0.0
-.TP
-.B \fBexample\fP:
-bridge\-mcsqi 31
-.UNINDENT
-.UNINDENT
-.UNINDENT
-.sp
-\fBbridge\-mcmi\fP
-.INDENT 0.0
-.INDENT 3.5
-\fBhelp\fP: set multicast membership interval (in secs)
-.sp
-\fBrequired\fP: False
-.sp
-\fBdefault\fP: 260
-.INDENT 0.0
-.TP
-.B \fBexample\fP:
-bridge\-mcmi 260
-.UNINDENT
-.UNINDENT
-.UNINDENT
-.sp
-\fBbridge\-ports\fP
-.INDENT 0.0
-.INDENT 3.5
-\fBhelp\fP: bridge ports
-.sp
-\fBrequired\fP: True
-.INDENT 0.0
-.TP
-.B \fBexample\fP:
-bridge\-ports swp1.100 swp2.100 swp3.100
-.sp
-bridge\-ports glob swp1\-3.100
-.sp
-bridge\-ports regex (swp[1|2|3].100)
-.UNINDENT
-.UNINDENT
-.UNINDENT
-.sp
-\fBbridge\-mcsnoop\fP
-.INDENT 0.0
-.INDENT 3.5
-\fBhelp\fP: set multicast snooping
-.sp
-\fBrequired\fP: False
-.sp
-\fBdefault\fP: 1
-.INDENT 0.0
-.TP
-.B \fBexample\fP:
-bridge\-mcsnoop 1
-.UNINDENT
-.UNINDENT
-.UNINDENT
-.sp
-\fBbridge\-maxwait\fP
-.INDENT 0.0
-.INDENT 3.5
-\fBhelp\fP: forces to time seconds the maximum time that the Deb
-ian bridge setup  scripts will wait for the bridge ports to ge
-t to the forwarding status, doesn\(aqt allow factional part. If i
-t is equal to 0 then no waiting is done
-.sp
-\fBrequired\fP: False
-.sp
-\fBdefault\fP: 0
-.INDENT 0.0
-.TP
-.B \fBexample\fP:
-bridge\-maxwait 3
-.UNINDENT
-.UNINDENT
-.UNINDENT
-.sp
-\fBbridge\-pathcosts\fP
-.INDENT 0.0
-.INDENT 3.5
-\fBhelp\fP: bridge set port path costs
-.sp
-\fBrequired\fP: False
-.sp
-\fBdefault\fP: 100
-.INDENT 0.0
-.TP
-.B \fBexample\fP:
-bridge\-pathcosts swp1=100 swp2=100
-.UNINDENT
-.UNINDENT
-.UNINDENT
-.sp
-\fBbridge\-portprios\fP
-.INDENT 0.0
-.INDENT 3.5
-\fBhelp\fP: bridge port prios
-.sp
-\fBrequired\fP: False
-.sp
-\fBdefault\fP: 32
-.INDENT 0.0
-.TP
-.B \fBexample\fP:
-bridge\-portprios swp1=32 swp2=32
-.UNINDENT
-.UNINDENT
-.UNINDENT
-.sp
-\fBbridge\-fd\fP
-.INDENT 0.0
-.INDENT 3.5
-\fBhelp\fP: bridge forward delay
-.sp
-\fBrequired\fP: False
-.sp
-\fBdefault\fP: 15
-.INDENT 0.0
-.TP
-.B \fBexample\fP:
-bridge\-fd 15
-.UNINDENT
-.UNINDENT
-.UNINDENT
-.sp
-\fBbridge\-ageing\fP
-.INDENT 0.0
-.INDENT 3.5
-\fBhelp\fP: bridge ageing
-.sp
-\fBrequired\fP: False
-.sp
-\fBdefault\fP: 300
-.INDENT 0.0
-.TP
-.B \fBexample\fP:
-bridge\-ageing 300
-.UNINDENT
-.UNINDENT
-.UNINDENT
-.sp
-\fBbridge\-hello\fP
-.INDENT 0.0
-.INDENT 3.5
-\fBhelp\fP: bridge set hello time
-.sp
-\fBrequired\fP: False
-.sp
-\fBdefault\fP: 2
-.INDENT 0.0
-.TP
-.B \fBexample\fP:
-bridge\-hello 2
-.UNINDENT
-.UNINDENT
-.UNINDENT
-.sp
-\fBbridge\-mcquerier\fP
-.INDENT 0.0
-.INDENT 3.5
-\fBhelp\fP: set multicast querier
-.sp
-\fBrequired\fP: False
-.sp
-\fBdefault\fP: 0
-.INDENT 0.0
-.TP
-.B \fBexample\fP:
-bridge\-mcquerier 0
-.UNINDENT
-.UNINDENT
-.UNINDENT
-.sp
-\fBbridge\-mclmc\fP
-.INDENT 0.0
-.INDENT 3.5
-\fBhelp\fP: set multicast last member count
-.sp
-\fBrequired\fP: False
-.sp
-\fBdefault\fP: 2
-.INDENT 0.0
-.TP
-.B \fBexample\fP:
-bridge\-mclmc 2
-.UNINDENT
-.UNINDENT
-.UNINDENT
-.sp
-\fBbridge\-mcrouter\fP
-.INDENT 0.0
-.INDENT 3.5
-\fBhelp\fP: set multicast router
-.sp
-\fBrequired\fP: False
-.sp
-\fBdefault\fP: 1
-.INDENT 0.0
-.TP
-.B \fBexample\fP:
-bridge\-mcrouter 1
-.UNINDENT
-.UNINDENT
-.UNINDENT
-.sp
-\fBbridge\-portmcrouter\fP
-.INDENT 0.0
-.INDENT 3.5
-\fBhelp\fP: set port multicast routers
-.sp
-\fBrequired\fP: False
-.sp
-\fBdefault\fP: 1
-.INDENT 0.0
-.TP
-.B \fBexample\fP:
-bridge\-portmcrouter swp1=1 swp2=1
-.UNINDENT
-.UNINDENT
-.UNINDENT
-.sp
-\fBbridge\-mclmi\fP
-.INDENT 0.0
-.INDENT 3.5
-\fBhelp\fP: set multicast last member interval (in secs)
-.sp
-\fBrequired\fP: False
-.sp
-\fBdefault\fP: 1
-.INDENT 0.0
-.TP
-.B \fBexample\fP:
-bridge\-mclmi 1
-.UNINDENT
-.UNINDENT
-.UNINDENT
-.sp
-\fBbridge\-hashmax\fP
-.INDENT 0.0
-.INDENT 3.5
-\fBhelp\fP: set hash max
-.sp
-\fBrequired\fP: False
-.sp
-\fBdefault\fP: 4096
-.INDENT 0.0
-.TP
-.B \fBexample\fP:
-bridge\-hashmax 4096
-.UNINDENT
-.UNINDENT
-.UNINDENT
-.sp
-\fBbridge\-waitport\fP
-.INDENT 0.0
-.INDENT 3.5
-\fBhelp\fP: wait for a max of time secs for the specified ports
-to become available,if no ports are specified then those speci
-fied on bridge\-ports will be used here. Specifying no ports he
-re should not be used if we are using regex or "all" on bridge
-_ports,as it wouldnt work.
-.sp
-\fBrequired\fP: False
-.sp
-\fBdefault\fP: 0
-.INDENT 0.0
-.TP
-.B \fBexample\fP:
-bridge\-waitport 4
-.UNINDENT
-.UNINDENT
-.UNINDENT
-.sp
-\fBbridge\-mcqri\fP
-.INDENT 0.0
-.INDENT 3.5
-\fBhelp\fP: set multicast query response interval (in secs)
-.sp
-\fBrequired\fP: False
-.sp
-\fBdefault\fP: 10
-.INDENT 0.0
-.TP
-.B \fBexample\fP:
-bridge\-mcqri 10
-.UNINDENT
-.UNINDENT
-.UNINDENT
-.sp
-\fBbridge\-hashel\fP
-.INDENT 0.0
-.INDENT 3.5
-\fBhelp\fP: set hash elasticity
-.sp
-\fBrequired\fP: False
-.sp
-\fBdefault\fP: 4096
-.INDENT 0.0
-.TP
-.B \fBexample\fP:
-bridge\-hashel 4096
-.UNINDENT
-.UNINDENT
-.UNINDENT
-.sp
-\fBbridge\-mcqpi\fP
-.INDENT 0.0
-.INDENT 3.5
-\fBhelp\fP: set multicast querier interval (in secs)
-.sp
-\fBrequired\fP: False
-.sp
-\fBdefault\fP: 255
-.INDENT 0.0
-.TP
-.B \fBexample\fP:
-bridge\-mcqpi 255
-.UNINDENT
-.UNINDENT
-.UNINDENT
-.sp
-\fBbridge\-bridgeprio\fP
-.INDENT 0.0
-.INDENT 3.5
-\fBhelp\fP: bridge priority
-.sp
-\fBrequired\fP: False
-.sp
-\fBdefault\fP: 32768
-.INDENT 0.0
-.TP
-.B \fBexample\fP:
-bridge\-bridgeprio 32768
-.UNINDENT
-.UNINDENT
-.UNINDENT
-.sp
-\fBbridge\-maxage\fP
-.INDENT 0.0
-.INDENT 3.5
-\fBhelp\fP: bridge set maxage
-.sp
-\fBrequired\fP: False
-.sp
-\fBdefault\fP: 20
-.INDENT 0.0
-.TP
-.B \fBexample\fP:
-bridge\-maxage 20
-.UNINDENT
-.UNINDENT
-.UNINDENT
-.sp
-\fBbridge\-portmcfl\fP
-.INDENT 0.0
-.INDENT 3.5
-\fBhelp\fP: port multicast fast leave
-.sp
-\fBrequired\fP: False
-.sp
-\fBdefault\fP: 0
-.INDENT 0.0
-.TP
-.B \fBexample\fP:
-bridge\-portmcfl swp1=0 swp2=0
-.UNINDENT
-.UNINDENT
-.UNINDENT
-.sp
-\fBbridge\-mcqi\fP
-.INDENT 0.0
-.INDENT 3.5
-\fBhelp\fP: set multicast query interval (in secs)
-.sp
-\fBrequired\fP: False
-.sp
-\fBdefault\fP: 125
-.INDENT 0.0
-.TP
-.B \fBexample\fP:
-bridge\-mcqi 125
-.UNINDENT
-.UNINDENT
-.UNINDENT
-.UNINDENT
-.UNINDENT
-.sp
-\fBusercmds\fP: user commands for interfaces
-.INDENT 0.0
-.INDENT 3.5
-\fBdown\fP
-.INDENT 0.0
-.INDENT 3.5
-\fBhelp\fP: run command at interface down
-.sp
-\fBrequired\fP: False
-.UNINDENT
-.UNINDENT
-.sp
-\fBpost\-up\fP
-.INDENT 0.0
-.INDENT 3.5
-\fBhelp\fP: run command after interface bring up
-.sp
-\fBrequired\fP: False
-.UNINDENT
-.UNINDENT
-.sp
-\fBup\fP
-.INDENT 0.0
-.INDENT 3.5
-\fBhelp\fP: run command at interface bring up
-.sp
-\fBrequired\fP: False
-.UNINDENT
-.UNINDENT
-.sp
-\fBpre\-down\fP
-.INDENT 0.0
-.INDENT 3.5
-\fBhelp\fP: run command before bringing the interface down
-.sp
-\fBrequired\fP: False
-.UNINDENT
-.UNINDENT
-.sp
-\fBpre\-up\fP
-.INDENT 0.0
-.INDENT 3.5
-\fBhelp\fP: run command before bringing the interface up
-.sp
-\fBrequired\fP: False
-.UNINDENT
-.UNINDENT
-.sp
-\fBpost\-down\fP
-.INDENT 0.0
-.INDENT 3.5
-\fBhelp\fP: run command after bringing interface down
-.sp
-\fBrequired\fP: False
-.UNINDENT
-.UNINDENT
-.UNINDENT
-.UNINDENT
-.sp
-\fBmstpctl\fP: mstp configuration module for bridges
-.INDENT 0.0
-.INDENT 3.5
-\fBmstpctl\-fdelay\fP
-.INDENT 0.0
-.INDENT 3.5
-\fBhelp\fP: set forwarding delay
-.sp
-\fBrequired\fP: False
-.sp
-\fBdefault\fP: 15
-.INDENT 0.0
-.TP
-.B \fBexample\fP:
-mstpctl\-fdelay 15
-.UNINDENT
-.UNINDENT
-.UNINDENT
-.sp
-\fBmstpctl\-txholdcount\fP
-.INDENT 0.0
-.INDENT 3.5
-\fBhelp\fP: bridge transmit holdcount
-.sp
-\fBrequired\fP: False
-.sp
-\fBdefault\fP: 6
-.INDENT 0.0
-.TP
-.B \fBexample\fP:
-mstpctl\-txholdcount 6
-.UNINDENT
-.UNINDENT
-.UNINDENT
-.sp
-\fBmstpctl\-portautoedge\fP
-.INDENT 0.0
-.INDENT 3.5
-\fBhelp\fP: enable/disable auto transition to/from edge state of
-the port
-.sp
-\fBrequired\fP: False
-.sp
-\fBdefault\fP: no
-.sp
-\fBvalidvals\fP: yes,no
-.INDENT 0.0
-.TP
-.B \fBexample\fP:
-mstpctl\-portautoedge swp1=yes swp2=yes
-.UNINDENT
-.UNINDENT
-.UNINDENT
-.sp
-\fBmstpctl\-portrestrrole\fP
-.INDENT 0.0
-.INDENT 3.5
-\fBhelp\fP: enable/disable port ability to take root role of the
-port
-.sp
-\fBrequired\fP: False
-.sp
-\fBdefault\fP: no
-.sp
-\fBvalidvals\fP: yes,no
-.INDENT 0.0
-.TP
-.B \fBexample\fP:
-mstpctl\-portrestrrole swp1=no swp2=no
-.UNINDENT
-.UNINDENT
-.UNINDENT
-.sp
-\fBmstpctl\-portnetwork\fP
-.INDENT 0.0
-.INDENT 3.5
-\fBhelp\fP: enable/disable bridge assurance capability for a por
-t
-.sp
-\fBrequired\fP: False
-.sp
-\fBdefault\fP: no
-.sp
-\fBvalidvals\fP: yes,no
-.INDENT 0.0
-.TP
-.B \fBexample\fP:
-mstpctl\-portnetwork swp1=no swp2=no
-.UNINDENT
-.UNINDENT
-.UNINDENT
-.sp
-\fBmstpctl\-portp2p\fP
-.INDENT 0.0
-.INDENT 3.5
-\fBhelp\fP: bridge port p2p detection mode
-.sp
-\fBrequired\fP: False
-.sp
-\fBdefault\fP: no
-.sp
-\fBvalidvals\fP: yes,no
-.INDENT 0.0
-.TP
-.B \fBexample\fP:
-mstpctl\-portp2p swp1=no swp2=no
-.UNINDENT
-.UNINDENT
-.UNINDENT
-.sp
-\fBmstpctl\-treeprio\fP
-.INDENT 0.0
-.INDENT 3.5
-\fBhelp\fP: tree priority
-.sp
-\fBrequired\fP: False
-.sp
-\fBdefault\fP: 32768
-.sp
-validrange: 0\-65535
-.INDENT 0.0
-.TP
-.B \fBexample\fP:
-mstpctl\-treeprio 32768
-.UNINDENT
-.UNINDENT
-.UNINDENT
-.sp
-\fBmstpctl\-treeportprio\fP
-.INDENT 0.0
-.INDENT 3.5
-\fBhelp\fP: port priority for MSTI instance
-.sp
-\fBrequired\fP: False
-.sp
-\fBdefault\fP: 128
-.sp
-validrange: 0\-240
-.INDENT 0.0
-.TP
-.B \fBexample\fP:
-mstpctl\-treeportprio swp1=128 swp2=128
-.UNINDENT
-.UNINDENT
-.UNINDENT
-.sp
-\fBmstpctl\-hello\fP
-.INDENT 0.0
-.INDENT 3.5
-\fBhelp\fP: set hello time
-.sp
-\fBrequired\fP: False
-.sp
-\fBdefault\fP: 2
-.INDENT 0.0
-.TP
-.B \fBexample\fP:
-mstpctl\-hello 2
-.UNINDENT
-.UNINDENT
-.UNINDENT
-.sp
-\fBmstpctl\-ageing\fP
-.INDENT 0.0
-.INDENT 3.5
-\fBhelp\fP: ageing time
-.sp
-\fBrequired\fP: False
-.sp
-\fBdefault\fP: 300
-.INDENT 0.0
-.TP
-.B \fBexample\fP:
-mstpctl\-ageing 300
-.UNINDENT
-.UNINDENT
-.UNINDENT
-.sp
-\fBmstpctl\-portadminedge\fP
-.INDENT 0.0
-.INDENT 3.5
-\fBhelp\fP: enable/disable initial edge state of the port
-.sp
-\fBrequired\fP: False
-.sp
-\fBdefault\fP: no
-.sp
-\fBvalidvals\fP: yes,no
-.INDENT 0.0
-.TP
-.B \fBexample\fP:
-mstpctl\-portadminedge swp1=no swp2=no
-.UNINDENT
-.UNINDENT
-.UNINDENT
-.sp
-\fBmstpctl\-maxage\fP
-.INDENT 0.0
-.INDENT 3.5
-\fBhelp\fP: max message age
-.sp
-\fBrequired\fP: False
-.sp
-\fBdefault\fP: 20
-.INDENT 0.0
-.TP
-.B \fBexample\fP:
-mstpctl\-maxage 20
-.UNINDENT
-.UNINDENT
-.UNINDENT
-.sp
-\fBmstpctl\-maxhops\fP
-.INDENT 0.0
-.INDENT 3.5
-\fBhelp\fP: bridge max hops
-.sp
-\fBrequired\fP: False
-.sp
-\fBdefault\fP: 15
-.INDENT 0.0
-.TP
-.B \fBexample\fP:
-mstpctl\-maxhops 15
-.UNINDENT
-.UNINDENT
-.UNINDENT
-.sp
-\fBmstpctl\-portrestrtcn\fP
-.INDENT 0.0
-.INDENT 3.5
-\fBhelp\fP: enable/disable port ability to propagate received to
-pology change notification of the port
-.sp
-\fBrequired\fP: False
-.sp
-\fBdefault\fP: no
-.sp
-\fBvalidvals\fP: yes,no
-.INDENT 0.0
-.TP
-.B \fBexample\fP:
-mstpctl\-portrestrtcn swp1=no swp2=no
-.UNINDENT
-.UNINDENT
-.UNINDENT
-.sp
-\fBmstpctl\-portpathcost\fP
-.INDENT 0.0
-.INDENT 3.5
-\fBhelp\fP: bridge port path cost
-.sp
-\fBrequired\fP: False
-.sp
-\fBdefault\fP: 0
-.INDENT 0.0
-.TP
-.B \fBexample\fP:
-mstpctl\-portpathcost swp1=0 swp2=1
-.UNINDENT
-.UNINDENT
-.UNINDENT
-.sp
-\fBmstpctl\-portadminage\fP
-.INDENT 0.0
-.INDENT 3.5
-\fBhelp\fP: bridge port admin age
-.sp
-\fBrequired\fP: False
-.sp
-\fBdefault\fP: no
-.sp
-\fBvalidvals\fP: yes,no
-.INDENT 0.0
-.TP
-.B \fBexample\fP:
-mstpctl\-portadminage swp1=no swp2=no
-.UNINDENT
-.UNINDENT
-.UNINDENT
-.sp
-\fBmstpctl\-portbpdufilter\fP
-.INDENT 0.0
-.INDENT 3.5
-\fBhelp\fP: enable/disable bpdu filter on a port
-.sp
-\fBrequired\fP: False
-.sp
-\fBdefault\fP: no
-.sp
-\fBvalidvals\fP: yes,no
-.INDENT 0.0
-.TP
-.B \fBexample\fP:
-mstpctl\-portbpdufilter swp1=no swp2=no
-.UNINDENT
-.UNINDENT
-.UNINDENT
-.sp
-\fBmstpctl\-forcevers\fP
-.INDENT 0.0
-.INDENT 3.5
-\fBhelp\fP: bridge force stp version
-.sp
-\fBrequired\fP: False
-.sp
-\fBdefault\fP: rstp
-.INDENT 0.0
-.TP
-.B \fBexample\fP:
-mstpctl\-forcevers rstp
-.UNINDENT
-.UNINDENT
-.UNINDENT
-.sp
-\fBmstpctl\-treeportcost\fP
-.INDENT 0.0
-.INDENT 3.5
-\fBhelp\fP: port tree cost
-.sp
-\fBrequired\fP: False
-.UNINDENT
-.UNINDENT
-.sp
-\fBmstpctl\-bpduguard\fP
-.INDENT 0.0
-.INDENT 3.5
-\fBhelp\fP: enable/disable bpduguard
-.sp
-\fBrequired\fP: False
-.sp
-\fBdefault\fP: no
-.sp
-\fBvalidvals\fP: yes,no
-.INDENT 0.0
-.TP
-.B \fBexample\fP:
-mstpctl\-bpduguard swp1=no swp2=no
-.UNINDENT
-.UNINDENT
-.UNINDENT
-.UNINDENT
-.UNINDENT
-.sp
-\fBvlan\fP: vlan module configures vlan interfaces.This module under
-stands vlan interfaces with dot notations. eg swp1.100. Vlan inter
-faces with any other names need to have raw device and vlan id att
-ributes
-.INDENT 0.0
-.INDENT 3.5
-\fBvlan\-id\fP
-.INDENT 0.0
-.INDENT 3.5
-\fBhelp\fP: vlan id
-.sp
-\fBrequired\fP: False
-.UNINDENT
-.UNINDENT
-.sp
-\fBvlan\-raw\-device\fP
-.INDENT 0.0
-.INDENT 3.5
-\fBhelp\fP: vlan raw device
-.sp
-\fBrequired\fP: False
-.UNINDENT
-.UNINDENT
-.UNINDENT
-.UNINDENT
-.sp
-\fBifenslave\fP: bond configuration module
-.INDENT 0.0
-.INDENT 3.5
-\fBbond\-miimon\fP
-.INDENT 0.0
-.INDENT 3.5
-\fBhelp\fP: bond miimon
-.sp
-\fBrequired\fP: False
-.sp
-\fBdefault\fP: 0
-.sp
-validrange: 0\-255
-.INDENT 0.0
-.TP
-.B \fBexample\fP:
-bond\-miimon 0
-.UNINDENT
-.UNINDENT
-.UNINDENT
-.sp
-\fBbond\-slaves\fP
-.INDENT 0.0
-.INDENT 3.5
-\fBhelp\fP: bond slaves
-.sp
-\fBrequired\fP: True
-.INDENT 0.0
-.TP
-.B \fBexample\fP:
-bond\-slaves swp1 swp2
-.sp
-bond\-slaves glob swp1\-2
-.sp
-bond\-slaves regex (swp[1|2)
-.UNINDENT
-.UNINDENT
-.UNINDENT
-.sp
-\fBbond\-mode\fP
-.INDENT 0.0
-.INDENT 3.5
-\fBhelp\fP: bond mode
-.sp
-\fBrequired\fP: False
-.sp
-\fBdefault\fP: balance\-rr
-.sp
-\fBvalidvals\fP: balance\-rr,active\-backup,balance\-xor,broadcast,802.3ad,balance\-tlb,balance\-alb
-.INDENT 0.0
-.TP
-.B \fBexample\fP:
-bond\-mode 802.3ad
-.UNINDENT
-.UNINDENT
-.UNINDENT
-.sp
-\fBbond\-num\-grat\-arp\fP
-.INDENT 0.0
-.INDENT 3.5
-\fBhelp\fP: bond use carrier
-.sp
-\fBrequired\fP: False
-.sp
-\fBdefault\fP: 1
-.sp
-validrange: 0\-255
-.INDENT 0.0
-.TP
-.B \fBexample\fP:
-bond\-num\-grat\-arp 1
-.UNINDENT
-.UNINDENT
-.UNINDENT
-.sp
-\fBbond\-ad\-sys\-mac\-addr\fP
-.INDENT 0.0
-.INDENT 3.5
-\fBhelp\fP: 802.3ad system mac address
-.sp
-\fBrequired\fP: False
-.sp
-\fBdefault\fP: 00:00:00:00:00:00
-.INDENT 0.0
-.TP
-.B \fBexample\fP:
-bond\-ad\-sys\-mac\-addr 00:00:00:00:00:00
-.UNINDENT
-.UNINDENT
-.UNINDENT
-.sp
-\fBbond\-use\-carrier\fP
-.INDENT 0.0
-.INDENT 3.5
-\fBhelp\fP: bond use carrier
-.sp
-\fBrequired\fP: False
-.sp
-\fBdefault\fP: 1
-.sp
-\fBvalidvals\fP: 0,1
-.INDENT 0.0
-.TP
-.B \fBexample\fP:
-bond\-use\-carrier 1
-.UNINDENT
-.UNINDENT
-.UNINDENT
-.sp
-\fBbond\-lacp\-rate\fP
-.INDENT 0.0
-.INDENT 3.5
-\fBhelp\fP: bond use carrier
-.sp
-\fBrequired\fP: False
-.sp
-\fBdefault\fP: 0
-.sp
-\fBvalidvals\fP: 0,1
-.INDENT 0.0
-.TP
-.B \fBexample\fP:
-bond\-lacp\-rate 0
-.UNINDENT
-.UNINDENT
-.UNINDENT
-.sp
-\fBbond\-min\-links\fP
-.INDENT 0.0
-.INDENT 3.5
-\fBhelp\fP: bond min links
-.sp
-\fBrequired\fP: False
-.sp
-\fBdefault\fP: 0
-.INDENT 0.0
-.TP
-.B \fBexample\fP:
-bond\-min\-links 0
-.UNINDENT
-.UNINDENT
-.UNINDENT
-.sp
-\fBbond\-num\-unsol\-na\fP
-.INDENT 0.0
-.INDENT 3.5
-\fBhelp\fP: bond slave devices
-.sp
-\fBrequired\fP: False
-.sp
-\fBdefault\fP: 1
-.sp
-validrange: 0\-255
-.INDENT 0.0
-.TP
-.B \fBexample\fP:
-bond\-num\-unsol\-na 1
-.UNINDENT
-.UNINDENT
-.UNINDENT
-.sp
-\fBbond\-ad\-sys\-priority\fP
-.INDENT 0.0
-.INDENT 3.5
-\fBhelp\fP: 802.3ad system priority
-.sp
-\fBrequired\fP: False
-.sp
-\fBdefault\fP: 65535
-.INDENT 0.0
-.TP
-.B \fBexample\fP:
-bond\-ad\-sys\-priority 65535
-.UNINDENT
-.UNINDENT
-.UNINDENT
-.sp
-\fBbond\-xmit\-hash\-policy\fP
-.INDENT 0.0
-.INDENT 3.5
-\fBhelp\fP: bond slave devices
-.sp
-\fBrequired\fP: False
-.sp
-\fBdefault\fP: layer2
-.sp
-\fBvalidvals\fP: layer2,layer3+4,layer2+3
-.INDENT 0.0
-.TP
-.B \fBexample\fP:
-bond\-xmit\-hash\-policy layer2
-.UNINDENT
-.UNINDENT
-.UNINDENT
-.UNINDENT
-.UNINDENT
-.sp
-\fBaddress\fP: address configuration module for interfaces
-.INDENT 0.0
-.INDENT 3.5
-\fBbroadcast\fP
-.INDENT 0.0
-.INDENT 3.5
-\fBhelp\fP: broadcast address
-.sp
-\fBrequired\fP: False
-.INDENT 0.0
-.TP
-.B \fBexample\fP:
-broadcast 10.0.1.255
-.UNINDENT
-.UNINDENT
-.UNINDENT
-.sp
-\fBhwaddress\fP
-.INDENT 0.0
-.INDENT 3.5
-\fBhelp\fP: hw address
-.sp
-\fBrequired\fP: False
-.INDENT 0.0
-.TP
-.B \fBexample\fP:
-hwaddress 44:38:39:00:27:b8
-.UNINDENT
-.UNINDENT
-.UNINDENT
-.sp
-\fBalias\fP
-.INDENT 0.0
-.INDENT 3.5
-\fBhelp\fP: description/alias
-.sp
-\fBrequired\fP: False
-.INDENT 0.0
-.TP
-.B \fBexample\fP:
-alias testnetwork
-.UNINDENT
-.UNINDENT
-.UNINDENT
-.sp
-\fBaddress\fP
-.INDENT 0.0
-.INDENT 3.5
-\fBhelp\fP: ipv4 or ipv6 addresses
-.sp
-\fBrequired\fP: False
-.INDENT 0.0
-.TP
-.B \fBexample\fP:
-address 10.0.12.3/24
-.sp
-address 2000:1000:1000:1000:3::5/128
-.UNINDENT
-.UNINDENT
-.UNINDENT
-.sp
-\fBscope\fP
-.INDENT 0.0
-.INDENT 3.5
-\fBhelp\fP: scope
-.sp
-\fBrequired\fP: False
-.INDENT 0.0
-.TP
-.B \fBexample\fP:
-scope host
-.UNINDENT
-.UNINDENT
-.UNINDENT
-.sp
-\fBpreferred\-lifetime\fP
-.INDENT 0.0
-.INDENT 3.5
-\fBhelp\fP: preferred lifetime
-.sp
-\fBrequired\fP: False
-.INDENT 0.0
-.TP
-.B \fBexample\fP:
-preferred\-lifetime forever
-.sp
-preferred\-lifetime 10
-.UNINDENT
-.UNINDENT
-.UNINDENT
-.sp
-\fBgateway\fP
-.INDENT 0.0
-.INDENT 3.5
-\fBhelp\fP: default gateway
-.sp
-\fBrequired\fP: False
-.INDENT 0.0
-.TP
-.B \fBexample\fP:
-gateway 255.255.255.0
-.UNINDENT
-.UNINDENT
-.UNINDENT
-.sp
-\fBmtu\fP
-.INDENT 0.0
-.INDENT 3.5
-\fBhelp\fP: interface mtu
-.sp
-\fBrequired\fP: False
-.sp
-\fBdefault\fP: 1500
-.INDENT 0.0
-.TP
-.B \fBexample\fP:
-mtu 1600
-.UNINDENT
-.UNINDENT
-.UNINDENT
-.UNINDENT
-.UNINDENT
-.UNINDENT
-.UNINDENT
-.SH SEE ALSO
-.INDENT 0.0
-.INDENT 3.5
-interfaces(5),
-ifup(8),
-ip(8),
-mstpctl(8),
-brctl(8),
-ethtool(8)
-.UNINDENT
-.UNINDENT
-.SH AUTHOR
-roopa@cumulusnetworks.com
-.SH COPYRIGHT
-Copyright 2013 Cumulus Networks, Inc.  All rights reserved.
-.\" Generated by docutils manpage writer.
-.\" 
-.
diff --git a/ifupdown2/man/interfaces.5 b/ifupdown2/man/interfaces.5
deleted file mode 100644 (file)
index 68f7d48..0000000
+++ /dev/null
@@ -1,207 +0,0 @@
-.\" Man page generated from reStructeredText.
-.
-.TH INTERFACES 5 "2014-02-05" "0.1" ""
-.SH NAME
-interfaces \- network interface configuration for ifupdown
-.
-.nr rst2man-indent-level 0
-.
-.de1 rstReportMargin
-\\$1 \\n[an-margin]
-level \\n[rst2man-indent-level]
-level margin: \\n[rst2man-indent\\n[rst2man-indent-level]]
--
-\\n[rst2man-indent0]
-\\n[rst2man-indent1]
-\\n[rst2man-indent2]
-..
-.de1 INDENT
-.\" .rstReportMargin pre:
-. RS \\$1
-. nr rst2man-indent\\n[rst2man-indent-level] \\n[an-margin]
-. nr rst2man-indent-level +1
-.\" .rstReportMargin post:
-..
-.de UNINDENT
-. RE
-.\" indent \\n[an-margin]
-.\" old: \\n[rst2man-indent\\n[rst2man-indent-level]]
-.nr rst2man-indent-level -1
-.\" new: \\n[rst2man-indent\\n[rst2man-indent-level]]
-.in \\n[rst2man-indent\\n[rst2man-indent-level]]u
-..
-.SH DESCRIPTION
-.INDENT 0.0
-.INDENT 3.5
-\fB/etc/network/interfaces\fP contains network interface configuration
-information for the \fBifup(8)\fP, \fBifdown(8)\fP and \fBifquery(8)\fP commands.
-.sp
-This is where you configure how your system is connected to the network.
-.sp
-Lines starting with # are ignored. Note that end\-of\-line comments are
-NOT supported, comments must be on a line of their own.
-.sp
-A line may be extended across multiple lines by making the last character
-a backslash.
-.sp
-The file consists of zero or more "iface", "auto",  "allow\-"
-and "source" stanzas. Here is an example:
-.sp
-.nf
-.ft C
-auto lo eth0
-allow\-hotplug eth1
-
-iface lo inet loopback
-
-source /etc/network/interfaces.d/bridges
-
-iface eth0 inet static
-    address 192.168.1.1/24
-    up flush\-mail
-
-iface eth1 inet dhcp
-.ft P
-.fi
-.sp
-Lines beginning with the word "auto" are used to identify the physical
-interfaces to be brought up when ifup is run with the \-a option.
-(This option is used by the system boot scripts.) Physical interface names
-should follow the word "auto" on the same line.  There can be  multiple
-"auto"  stanzas.
-.sp
-Lines beginning with "allow\-" are  used  to  identify  interfaces  that
-should  be  brought  up automatically by various subsytems. This may be
-done using a command such as "ifup \-\-allow=hotplug  eth0  eth1",  which
-will  only  bring up eth0 or eth1 if it is listed in an "allow\-hotplug"
-line. Note that "allow\-auto" and "auto" are synonyms.
-.sp
-Lines beginning with "source" are used to include  stanzas  from  other
-files, so configuration can be split into many files. The word "source"
-is followed by the path of file to be sourced. Shell wildcards  can  be
-used. Currently only supports absolute
-path names.
-.sp
-iface is normally given a interface name as its first non\-option
-argument.
-.sp
-The interface name is followed by the name of the address family that the
-interface uses. This will be "inet" for TCP/IP networking and inet6 for
-ipv6. Following that is the name of the method used to configure the
-interface.
-.sp
-ifupdown supports iface stanzas without a family or a method. This enables
-using the same stanza for inet and inet6 family addresses. And the method
-defaults to "static"
-.sp
-Additional interface options/attributes can be given on subsequent lines
-in the iface stanza. These options come from addon modules. see
-\fBifupdown\-addons\-interfaces(5)\fP for these options.
-.sp
-example bridge interface with additional attributes listed in the
-\fBifupdown\-addons\-interfaces(5)\fP man page:
-.sp
-.nf
-.ft C
-auto br0
-iface br0
-    address 12.0.0.4/24
-    address 2000:1000:1000:1000:3::5/128
-    bridge\-ports swp1 swp2 swp3
-    bridge\-stp on
-.ft P
-.fi
-.sp
-ifupdown supports python\-mako style templates in the interfaces file.
-See examples section for details.
-.sp
-See \fB/usr/share/doc/python\-ifupdown2/examples/\fP for \fBinterfaces(5)\fP
-file examples and interfaces file generation scripts.
-.UNINDENT
-.UNINDENT
-.SH METHODS
-.INDENT 0.0
-.INDENT 3.5
-Both \fBinet\fP and \fBinet6\fP address family interfaces can use the following
-methods (However they are not required):
-.INDENT 0.0
-.TP
-.B The loopback Method
-This method may be used to define the loopback interface.
-.TP
-.B The static Method
-This method may be used to define ethernet interfaces with
-statically allocated addresses.
-.TP
-.B The dhcp Method
-This method may be used to obtain an address via DHCP.
-.UNINDENT
-.UNINDENT
-.UNINDENT
-.SH BUILTIN INTERFACES
-.INDENT 0.0
-.INDENT 3.5
-\fBiface\fP sections for some interfaces like physical interfaces or vlan
-interfaces in dot notation (like eth1.100) are understood by ifupdown.
-These interfaces do not need an entry in the interfaces file if
-they are dependents of other interfaces and dont need any specific
-configurations like addresses etc.
-.UNINDENT
-.UNINDENT
-.SH EXAMPLES
-.INDENT 0.0
-.INDENT 3.5
-Sample /etc/network/interfaces file:
-.sp
-.nf
-.ft C
-auto lo
-iface lo
-    address 192.168.2.0/24
-    address 2001:dee:eeee:1::4/128
-
-auto eth0
-iface eth0 inet dhcp
-
-auto eth1
-iface eth1 inet manual
-    address 192.168.2.0/24
-    address 2001:dee:eeee:1::4/128
-
-# source files from a directory /etc/network/interfaces.d
-source /etc/network/interfaces.d/*
-
-# Using mako style templates
-% for v in [11,12]:
-    auto vlan${v}
-    iface vlan${v} inet static
-        address 10.20.${v}.3/24
-% endfor
-.ft P
-.fi
-.sp
-For additional syntax and examples see \fBifupdown\-addons\-interfaces(5)\fP
-.UNINDENT
-.UNINDENT
-.SH FILES
-.INDENT 0.0
-.INDENT 3.5
-/etc/network/interfaces
-.UNINDENT
-.UNINDENT
-.SH SEE ALSO
-.INDENT 0.0
-.INDENT 3.5
-ifupdown\-addons\-interfaces(5),
-ifup(8),
-ifquery(8),
-ifreload(8)
-.UNINDENT
-.UNINDENT
-.SH AUTHOR
-Roopa Prabhu <roopa@cumulusnetworks.com>
-.SH COPYRIGHT
-Copyright 2014 Cumulus Networks, Inc.  All rights reserved.
-.\" Generated by docutils manpage writer.
-.\" 
-.
diff --git a/ifupdown2/sbin/ifupdown b/ifupdown2/sbin/ifupdown
deleted file mode 100755 (executable)
index d6bdeb2..0000000
+++ /dev/null
@@ -1,496 +0,0 @@
-#!/usr/bin/python
-#
-# Copyright 2014 Cumulus Networks, Inc. All rights reserved.
-# Author: Roopa Prabhu, roopa@cumulusnetworks.com
-#
-# ifupdown --
-#    tool to configure network interfaces
-#
-import sys
-import os
-import argcomplete
-import argparse
-import ConfigParser
-import StringIO
-import logging
-import logging.handlers
-import resource
-from ifupdown.ifupdownmain import *
-from ifupdown.utils import *
-
-lockfile="/run/network/.lock"
-configfile="/etc/network/ifupdown2/ifupdown2.conf"
-configmap_g=None
-logger = None
-interfacesfileiobuf=None
-ENVPATH = "/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"
-
-def run_up(args):
-    logger.debug('args = %s' %str(args))
-
-    try:
-        iflist = args.iflist
-        if len(args.iflist) == 0:
-            iflist = None
-        logger.debug('creating ifupdown object ..')
-        cachearg=(False if (iflist or args.nocache or
-                            args.perfmode or args.noact)
-                            else True)
-        ifupdown_handle = ifupdownMain(config=configmap_g,
-                                       force=args.force,
-                                       withdepends=args.withdepends,
-                                       perfmode=args.perfmode,
-                                       dryrun=args.noact,
-                                       cache=cachearg,
-                                       addons_enable=not args.noaddons,
-                                       statemanager_enable=not args.noaddons,
-                                       interfacesfile=args.interfacesfile,
-                                       interfacesfileiobuf=interfacesfileiobuf,
-                                       interfacesfileformat=args.interfacesfileformat)
-        if args.noaddons:
-            ifupdown_handle.up(['up'], args.all, args.CLASS, iflist,
-                               excludepats=args.excludepats,
-                               printdependency=args.printdependency,
-                               syntaxcheck=args.syntaxcheck, type=args.type,
-                               skipupperifaces=args.skipupperifaces)
-        else:
-            ifupdown_handle.up(['pre-up', 'up', 'post-up'],
-                               args.all, args.CLASS, iflist,
-                               excludepats=args.excludepats,
-                               printdependency=args.printdependency,
-                               syntaxcheck=args.syntaxcheck, type=args.type,
-                               skipupperifaces=args.skipupperifaces)
-    except:
-        raise
-
-def run_down(args):
-    logger.debug('args = %s' %str(args))
-
-    try:
-        iflist = args.iflist
-        logger.debug('creating ifupdown object ..')
-        ifupdown_handle = ifupdownMain(config=configmap_g, force=args.force,
-                                       withdepends=args.withdepends,
-                                       perfmode=args.perfmode,
-                                       dryrun=args.noact,
-                                       addons_enable=not args.noaddons,
-                                       statemanager_enable=not args.noaddons,
-                                       interfacesfile=args.interfacesfile,
-                                       interfacesfileiobuf=interfacesfileiobuf,
-                                       interfacesfileformat=args.interfacesfileformat)
-
-        ifupdown_handle.down(['pre-down', 'down', 'post-down'],
-                             args.all, args.CLASS, iflist,
-                             excludepats=args.excludepats,
-                             printdependency=args.printdependency,
-                             usecurrentconfig=args.usecurrentconfig,
-                             type=args.type)
-    except:
-        raise
-
-def run_query(args):
-    logger.debug('args = %s' %str(args))
-
-    try:
-        iflist = args.iflist
-        if args.checkcurr:
-            qop='query-checkcurr'
-        elif args.running:
-            qop='query-running'
-        elif args.raw:
-            qop='query-raw'
-        elif args.syntaxhelp:
-            qop = 'query-syntax'
-        elif args.printdependency:
-            qop = 'query-dependency'
-        elif args.printsavedstate:
-            qop = 'query-savedstate'
-        else:
-            qop='query'
-        cachearg=(False if (iflist or args.nocache or
-                            args.perfmode or args.syntaxhelp or
-                            (qop != 'query-checkcurr' and
-                            qop != 'query-running')) else True)
-        if not iflist and qop == 'query-running':
-            iflist = [i for i in os.listdir('/sys/class/net/')
-                        if os.path.isdir('/sys/class/net/%s' %i)]
-        logger.debug('creating ifupdown object ..')
-        ifupdown_handle = ifupdownMain(config=configmap_g,
-                                       withdepends=args.withdepends,
-                                       perfmode=args.perfmode,
-                                       cache=cachearg,
-                                       interfacesfile=args.interfacesfile,
-                                       interfacesfileiobuf=interfacesfileiobuf,
-                                       interfacesfileformat=args.interfacesfileformat)
-
-        ifupdown_handle.query([qop], args.all, args.CLASS, iflist,
-                              excludepats=args.excludepats,
-                              printdependency=args.printdependency,
-                              format=args.format, type=args.type)
-    except:
-        raise
-
-def run_reload(args):
-    logger.debug('args = %s' %str(args))
-
-    try:
-        logger.debug('creating ifupdown object ..')
-        ifupdown_handle = ifupdownMain(config=configmap_g,
-                                       withdepends=args.withdepends,
-                                       perfmode=args.perfmode)
-        ifupdown_handle.reload(['pre-up', 'up', 'post-up'],
-                               ['pre-down', 'down', 'post-down'],
-                               auto=args.all, allow=None, ifacenames=None,
-                               excludepats=args.excludepats,
-                               usecurrentconfig=args.usecurrentconfig,
-                               currentlyup=args.currentlyup)
-    except:
-        raise
-
-def init(args):
-    global logger
-    global interfacesfileiobuf
-
-    log_level = logging.WARNING
-    if args.verbose:
-        log_level = logging.INFO
-    if args.debug:
-        log_level = logging.DEBUG
-
-    try:
-        if hasattr(args, 'syslog') and args.syslog:
-            root_logger = logging.getLogger()
-            syslog_handler = logging.handlers.SysLogHandler(address='/dev/log',
-                             facility=logging.handlers.SysLogHandler.LOG_DAEMON)
-            logging.addLevelName(logging.ERROR, 'error')
-            logging.addLevelName(logging.WARNING, 'warning')
-            logging.addLevelName(logging.DEBUG, 'debug')
-            logging.addLevelName(logging.INFO, 'info')
-            root_logger.setLevel(log_level)
-            syslog_handler.setFormatter(logging.Formatter(
-                '%(name)s: %(levelname)s: %(message)s'))
-            root_logger.addHandler(syslog_handler)
-            logger = logging.getLogger('ifupdown')
-        else:
-            logging.basicConfig(level=log_level,
-                format='%(levelname)s: %(message)s')
-            logging.addLevelName(logging.ERROR, 'error')
-            logging.addLevelName(logging.WARNING, 'warning')
-            logging.addLevelName(logging.DEBUG, 'debug')
-            logging.addLevelName(logging.INFO, 'info')
-            logger = logging.getLogger('ifupdown')
-    except:
-        raise
-
-    # If interfaces file is stdin, read
-    if hasattr(args, 'interfacesfile') and args.interfacesfile == '-':
-        interfacesfileiobuf = sys.stdin.read()
-
-def deinit():
-    {}
-
-def update_argparser(argparser):
-    """ base parser, common to all commands """
-
-    argparser.add_argument('-a', '--all', action='store_true', required=False,
-                help='process all interfaces marked \"auto\"')
-    argparser.add_argument('iflist', metavar='IFACE',
-                nargs='*', help='interface list separated by spaces. ' +
-                'IFACE list is mutually exclusive with -a option.')
-    argparser.add_argument('-v', '--verbose', dest='verbose',
-                action='store_true', help='verbose')
-    argparser.add_argument('-d', '--debug', dest='debug',
-                action='store_true',
-                help='output debug info')
-    argparser.add_argument('-q', '--quiet', dest='quiet',
-                action='store_true',
-                help=argparse.SUPPRESS)
-    argparser.add_argument('--allow', dest='CLASS', 
-                help='ignore non-\"allow-CLASS\" interfaces')
-    argparser.add_argument('-w', '--with-depends', dest='withdepends',
-                action='store_true', help='run with all dependent interfaces.'+
-                ' This option is redundant when \'-a\' is specified. With ' +
-                '\'-a\' interfaces are always executed in dependency order')
-    argparser.add_argument('--perfmode', dest='perfmode',
-                action='store_true', help=argparse.SUPPRESS)
-    #argparser.add_argument('-j', '--jobs', dest='jobs', type=int,
-    #            default=-1, choices=range(1,12), help=argparse.SUPPRESS)
-    argparser.add_argument('--nocache', dest='nocache', action='store_true',
-                help=argparse.SUPPRESS)
-    argparser.add_argument('-X', '--exclude', dest='excludepats',
-                action='append',
-                help='Exclude interfaces from the list of interfaces' +
-                ' to operate on. Can be specified multiple times.')
-    argparser.add_argument('-i', '--interfaces', dest='interfacesfile',
-                default='/etc/network/interfaces',
-                help='use interfaces file instead of default ' +
-                '/etc/network/interfaces')
-    argparser.add_argument('-t', '--interfaces-format',
-                dest='interfacesfileformat',
-                default='native',
-                choices=['native', 'json'],
-                help='interfaces file format')
-    argparser.add_argument('-T', '--type',
-                dest='type',
-                default=None,
-                choices=['iface', 'vlan'],
-                help='type of interface entry (iface or vlan).' +
-                     'This option can be used in case of ambiguity between ' +
-                     'a vlan interface and an iface interface of the same name')
-
-def update_ifupdown_argparser(argparser):
-    """ common arg parser for ifup and ifdown """
-    argparser.add_argument('-f', '--force', dest='force',
-                action='store_true',
-                help='force run all operations')
-    argparser.add_argument('-l', '--syslog', dest='syslog',
-                action='store_true',
-                help=argparse.SUPPRESS)
-    group = argparser.add_mutually_exclusive_group(required=False)
-    group.add_argument('-n', '--no-act', dest='noact',
-                action='store_true', help='print out what would happen,' +
-                'but don\'t do it')
-    group.add_argument('-p', '--print-dependency',
-                dest='printdependency', choices=['list', 'dot'],
-                help='print iface dependency')
-    group.add_argument('--no-scripts', '--admin-state',
-                dest='noaddons',  action='store_true',
-                help='dont run any addon modules/scripts. Only bring the ' +
-                    'interface administratively up/down')
-
-def update_ifup_argparser(argparser):
-    argparser.add_argument('-s', '--syntax-check', dest='syntaxcheck',
-                action='store_true',
-                help='Only run the interfaces file parser')
-    argparser.add_argument('-k', '--skip-upperifaces', dest='skipupperifaces',
-                action='store_true',
-                help='ifup by default tries to add newly created interfaces' +
-                ' into its upper/parent interfaces. Eg. if a bridge port is' +
-                ' created as a result of ifup on the port, ifup automatically' +
-                ' adds the port to the bridge. This option can be used to ' +
-                'disable this default behaviour')
-    update_ifupdown_argparser(argparser)
-
-def update_ifdown_argparser(argparser):
-    update_ifupdown_argparser(argparser)
-    argparser.add_argument('-u', '--use-current-config',
-                dest='usecurrentconfig',  action='store_true',
-                help='By default ifdown looks at the saved state for ' +
-                'interfaces to bring down. This option allows ifdown to ' +
-                'look at the current interfaces file. Useful when your ' +
-                'state file is corrupted or you want down to use the latest '
-                'from the interfaces file')
-
-def update_ifquery_argparser(argparser):
-    """ arg parser for ifquery options """
-
-    # -l is same as '-a', only here for backward compatibility
-    argparser.add_argument('-l', '--list', action='store_true', dest='all',
-                help=argparse.SUPPRESS)
-    group = argparser.add_mutually_exclusive_group(required=False)
-    group.add_argument('-r', '--running', dest='running',
-                       action='store_true',
-                       help='query running state of an interface')
-    group.add_argument('-c', '--check', dest='checkcurr',
-                       action='store_true',
-                       help='check interface file contents against ' +
-                       'running state of an interface')
-    group.add_argument('-x', '--raw', action='store_true', dest='raw',
-                       help='print raw config file entries')
-    group.add_argument('--print-savedstate', action='store_true',
-                       dest='printsavedstate',
-                       help=argparse.SUPPRESS)
-    argparser.add_argument('-o', '--format', dest='format', default='native',
-                           choices=['native', 'json'],
-                           help='interface display format')
-    argparser.add_argument('-p', '--print-dependency',
-                           dest='printdependency', choices=['list', 'dot'],
-                           help='print interface dependency')
-    argparser.add_argument('-s', '--syntax-help', action='store_true',
-                           dest='syntaxhelp',
-                           help='print supported interface config syntax')
-
-def update_ifreload_argparser(argparser):
-    """ parser for ifreload """
-    group = argparser.add_mutually_exclusive_group(required=True)
-    group.add_argument('-a', '--all', action='store_true',
-                help='process all interfaces marked \"auto\"')
-    group.add_argument('-c', '--currently-up', dest='currentlyup',
-                action='store_true',
-                help='only reload auto and other interfaces that are ' +
-                'currently up')
-    argparser.add_argument('iflist', metavar='IFACE',
-                nargs='*', help=argparse.SUPPRESS)
-    argparser.add_argument('-n', '--no-act', dest='noact',
-                action='store_true', help=argparse.SUPPRESS)
-    argparser.add_argument('-v', '--verbose', dest='verbose',
-                action='store_true', help='verbose')
-    argparser.add_argument('-d', '--debug', dest='debug',
-                action='store_true',
-                help='output debug info')
-    argparser.add_argument('-w', '--with-depends', dest='withdepends',
-                action='store_true', help=argparse.SUPPRESS)
-    argparser.add_argument('--perfmode', dest='perfmode',
-                action='store_true', help=argparse.SUPPRESS)
-    argparser.add_argument('--nocache', dest='nocache', action='store_true',
-                help=argparse.SUPPRESS)
-    argparser.add_argument('-X', '--exclude', dest='excludepats',
-                action='append',
-                help=argparse.SUPPRESS)
-    #argparser.add_argument('-j', '--jobs', dest='jobs', type=int,
-    #            default=-1, choices=range(1,12), help=argparse.SUPPRESS)
-    #argparser.add_argument('-i', '--interfaces', dest='interfacesfile',
-    #            default='/etc/network/interfaces',
-    #            help='use interfaces file instead of default ' +
-    #            '/etc/network/interfaces')
-    argparser.add_argument('-u', '--use-current-config',
-                dest='usecurrentconfig',  action='store_true',
-                help='By default ifreload looks at saved state for ' +
-                'interfaces to bring down. With this option ifreload will'
-                ' only look at the current interfaces file. Useful when your ' +
-                'state file is corrupted or you want down to use the latest '
-                'from the interfaces file')
-    argparser.add_argument('-l', '--syslog', dest='syslog',
-                action='store_true',
-                help=argparse.SUPPRESS)
-    argparser.add_argument('-f', '--force', dest='force',
-                action='store_true',
-                help='force run all operations')
-
-def parse_args(argsv, op):
-    if op == 'query':
-        descr = 'query interfaces (all or interface list)'
-    elif op == 'reload':
-        descr = 'reload interface configuration.'
-    else:
-        descr = 'interface management'
-    argparser = argparse.ArgumentParser(description=descr)
-    if op == 'reload':
-        update_ifreload_argparser(argparser)
-    else:
-        update_argparser(argparser)
-        if op == 'up':
-            update_ifup_argparser(argparser)
-        elif op == 'down':
-            update_ifdown_argparser(argparser)
-        elif op == 'query':
-            update_ifquery_argparser(argparser)
-        elif op == 'reload':
-            update_ifreload_argparser(argparser)
-    argcomplete.autocomplete(argparser)
-    return argparser.parse_args(argsv)
-
-handlers = {'up' : run_up,
-            'down' : run_down,
-            'query' : run_query,
-            'reload' : run_reload }
-
-def validate_args(op, args):
-    #if op == 'up' and args.syntaxcheck:
-    #    if args.iflist or args.all:
-    #        print 'ignoring interface options ..'
-    #    return True
-    if op == 'query' and args.syntaxhelp:
-        return True
-    if op == 'reload':
-        if not args.all and not args.currentlyup:
-            print '\'-a\' or \'-c\' option is required'
-            return False
-    elif (not args.iflist and
-            not args.all and not args.CLASS):
-        print '\'-a\' option or interface list are required'
-        return False
-    if args.iflist and args.all:
-        print '\'-a\' option and interface list are mutually exclusive'
-        return False
-    if op != 'reload' and args.CLASS and (args.all or args.iflist):
-        print ('\'--allow\' option is mutually exclusive ' +
-               'with interface list and \'-a\'')
-        return False
-    return True
-
-def read_config(args):
-    global configmap_g
-
-    config = open(configfile, 'r').read()
-    configStr = '[ifupdown2]\n' + config
-    configFP =  StringIO.StringIO(configStr)
-    parser = ConfigParser.RawConfigParser()
-    parser.readfp(configFP)
-    configmap_g = dict(parser.items('ifupdown2'))
-
-    # Preprocess config map
-    configval = configmap_g.get('multiple_vlan_aware_bridge_support', '0')
-    if configval == '0':
-        # if multiple bridges not allowed, set the bridge-vlan-aware
-        # attribute in the 'no_repeats' config, so that the ifupdownmain
-        # module can catch it appropriately
-        configmap_g['no_repeats'] = {'bridge-vlan-aware' : 'yes'}
-
-
-    configval = configmap_g.get('link_master_slave', '0')
-    if configval == '1':
-        # link_master_slave is only valid when all is set
-        if hasattr(args, 'all') and not args.all:
-            configmap_g['link_master_slave'] = '0'
-
-    configval = configmap_g.get('delay_admin_state_change', '0')
-    if configval == '1':
-        # reset link_master_slave if delay_admin_state_change is on
-        configmap_g['link_master_slave'] = '0'
-
-def main(argv):
-    """ main function """
-    args = None
-    try:
-        op = None
-        if argv[0].endswith('ifup'):
-            op = 'up'
-        elif argv[0].endswith('ifdown'):
-            op = 'down'
-        elif argv[0].endswith('ifquery'):
-            op = 'query'
-        elif argv[0].endswith('ifreload'):
-            op = 'reload'
-        else:
-            print ('Unexpected executable.' +
-                   ' Should be \'ifup\' or \'ifdown\' or \'ifquery\'')
-            exit(1)
-        # Command line arg parser
-        args = parse_args(argv[1:], op)
-        if not validate_args(op, args):
-            exit(1)
-
-        if not sys.argv[0].endswith('ifquery') and not os.geteuid() == 0:
-            print 'error: must be root to run this command'
-            exit(1)
-
-        if not sys.argv[0].endswith('ifquery') and not utils.lockFile(lockfile):
-            print 'Another instance of this program is already running.'
-            exit(0)
-
-        read_config(args)
-        init(args)
-        handlers.get(op)(args)
-    except Exception, e:
-        if not str(e):
-            exit(1)
-        if args and args.debug:
-            raise
-        else:
-            if logger:
-                logger.error(str(e))
-            else:
-                print str(e)
-            #if args and not args.debug:
-            #    print '\nrerun the command with \'-d\' for a detailed errormsg'
-        exit(1)
-    finally:
-        deinit()
-
-if __name__ == "__main__":
-
-    # required during boot
-    os.putenv('PATH', ENVPATH)
-    resource.setrlimit(resource.RLIMIT_CORE, (0,0))
-    main(sys.argv)
diff --git a/ifupdown2/scripts/genmanpages.sh b/ifupdown2/scripts/genmanpages.sh
deleted file mode 100755 (executable)
index 2553dc7..0000000
+++ /dev/null
@@ -1,28 +0,0 @@
-#!/bin/sh
-#
-# Copyright 2013 Cumulus Networks, Inc.
-# All rights reserved.
-#
-
-# Install the man pages into the sysroot
-SRC_MAN_DIR=$1
-DST_MAN_DIR=$2
-
-echo -n "Generating man pages .."
-# Loop over all the man directories
-mkdir -p $DST_MAN_DIR
-for p in $(ls $SRC_MAN_DIR/*.rst) ; do
-    # strip src man path
-    src_file=$p
-    dst_file=${p##.*\/}
-    dst_file="${DST_MAN_DIR}/${dst_file%.rst}"
-    # treat warnings as errors
-    rst2man --halt=2 "$p" > $dst_file || {
-        echo
-        echo "Error: problems generating man page: $p"
-        rm -f $dst_file &>/dev/null
-        exit 1
-    }
-    echo -n "."
-done
-echo " done."
diff --git a/ifupdown2/setup.py b/ifupdown2/setup.py
deleted file mode 100755 (executable)
index 015a550..0000000
+++ /dev/null
@@ -1,47 +0,0 @@
-from distutils.core import setup
-
-setup(name='ifupdown2',
-      version='0.1',
-      description = "ifupdown 2",
-      author='Roopa Prabhu',
-      author_email='roopa@cumulusnetworks.com',
-      url='cumulusnetworks.com',
-      packages=['ifupdown', 'ifupdownaddons'],
-      scripts = ['sbin/ifupdown'],
-      install_requires = ['python-gvgen', 'python-argcomplete', 'python-ipaddr'],
-      data_files=[('share/man/man8/',
-                      ['man/ifup.8', 'man/ifquery.8', 'man/ifreload.8']),
-                  ('share/man/man5/',
-                      ['man/interfaces.5', 'man/ifupdown-addons-interfaces.5']),
-                  ('/etc/init.d/',
-                      ['init.d/networking']),
-                  ('/sbin/', ['sbin/ifupdown']),
-                  ('/etc/network/ifupdown2/',
-                      ['config/ifupdown2.conf']),
-                  ('/etc/default/',
-                      ['config/networking']),
-                  ('/usr/share/python-ifupdown2/',
-                      ['docs/examples/generate_interfaces.py']),
-                  ('/usr/share/doc/python-ifupdown2/examples/',
-                      ['docs/examples/interfaces',
-                       'docs/examples/interfaces_bridge_template_func',
-                       'docs/examples/interfaces_with_template',
-                       'docs/examples/interfaces_bridge_igmp_mstp']),
-                  ('/usr/share/doc/python-ifupdown2/examples/vlan_aware_bridges',
-                      ['docs/examples/vlan_aware_bridges/interfaces.basic',
-                       'docs/examples/vlan_aware_bridges/interfaces.vlan_prune_and_access_ports',
-                       'docs/examples/vlan_aware_bridges/interfaces.with_bonds',
-                       'docs/examples/vlan_aware_bridges/interfaces.with_clag']),
-                  ('/etc/bash_completion.d/', ['completion/ifup']),
-                  ('/usr/share/ifupdownaddons/', ['addons/bridge.py',
-                      'addons/ifenslave.py', 'addons/vlan.py',
-                      'addons/mstpctl.py', 'addons/address.py',
-                      'addons/dhcp.py', 'addons/usercmds.py',
-                      'addons/ethtool.py', 'addons/loopback.py',
-                      'addons/addressvirtual.py', 'addons/vxlan.py',
-                      'addons/bridgevlan.py']),
-                  ('/var/lib/ifupdownaddons/', ['config/addons.conf']),
-                  ('/var/lib/ifupdownaddons/policy.d/', []),
-                  ('/etc/network/ifupdown2/policy.d/', [])
-                  ]
-      )
diff --git a/ifupdown2/stdeb.cfg b/ifupdown2/stdeb.cfg
deleted file mode 100644 (file)
index db6414a..0000000
+++ /dev/null
@@ -1,2 +0,0 @@
-[DEFAULT]
-Conflicts: ifupdown
diff --git a/ifupdown2/tests/ifstatetest b/ifupdown2/tests/ifstatetest
deleted file mode 100755 (executable)
index a761e75..0000000
+++ /dev/null
@@ -1,56 +0,0 @@
-#!/usr/bin/python
-
-""" test for testing and profiling state manager """
-
-import cProfile
-
-from ifupdown.networkinterfaces import *
-from ifupdown.iface import *
-from ifupdown.statemanager import pickling
-import os
-
-ifaceobjdict = {}
-state_file = '/tmp/ifstatetest'
-
-def save_iface(ifaceobj):
-    ifaceobjdict[ifaceobj.get_name()] = ifaceobj
-    
-def read_default_iface_config():
-    """ Reads default network interface config /etc/network/interfaces. """
-    nifaces = networkInterfaces()
-    nifaces.subscribe('iface_found', save_iface)
-    nifaces.load()
-
-def save_state():
-    try:
-        with open(state_file, 'w') as f:
-            for ifaceobj in ifaceobjdict.values():
-                pickling.save_obj(f, ifaceobj)
-    except:
-        raise
-
-def load_state():
-    global ifaceobjdict
-
-    if not os.path.exists(state_file):
-        return
-
-    del ifaceobjdict
-    ifaceobjdict = {}
-
-    # Read all ifaces from file
-    for ifaceobj in pickling.load(state_file):
-        save_iface(ifaceobj)
-
-
-print 'Reading iface config files ..'
-cProfile.run('read_default_iface_config()')
-print 'number of objects: %d' %len(ifaceobjdict)
-
-print 'saving iface state ..'
-cProfile.run('save_state()')
-
-print 'loading iface state ..'
-cProfile.run('load_state()')
-print 'number of objects: %d' %len(ifaceobjdict)
-
diff --git a/ifupdownaddons/__init__.py b/ifupdownaddons/__init__.py
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/ifupdownaddons/bridgeutils.py b/ifupdownaddons/bridgeutils.py
new file mode 100644 (file)
index 0000000..73f28b1
--- /dev/null
@@ -0,0 +1,501 @@
+#!/usr/bin/python
+#
+# Copyright 2014 Cumulus Networks, Inc. All rights reserved.
+# Author: Roopa Prabhu, roopa@cumulusnetworks.com
+#
+
+from ifupdown.iface import *
+from utilsbase import *
+import os
+import re
+import logging
+from cache import *
+
+class brctl(utilsBase):
+    """ This class contains helper functions to interact with the bridgeutils
+    commands """
+
+    _cache_fill_done = False
+
+    def __init__(self, *args, **kargs):
+        utilsBase.__init__(self, *args, **kargs)
+        if self.CACHE and not brctl._cache_fill_done:
+            self._bridge_fill()
+            brctl._cache_fill_done = True
+
+
+    def _bridge_get_mcattrs_from_sysfs(self, bridgename):
+        mcattrs = {}
+        mcattrmap = {'mclmc': 'multicast_last_member_count',
+                     'mcrouter': 'multicast_router',
+                     'mcsnoop' : 'multicast_snooping',
+                     'mcsqc' : 'multicast_startup_query_count',
+                     'mcqifaddr' : 'multicast_query_use_ifaddr',
+                     'mcquerier' : 'multicast_querier',
+                     'hashel' : 'hash_elasticity',
+                     'hashmax' : 'hash_max',
+                     'mclmi' : 'multicast_last_member_interval',
+                     'mcmi' : 'multicast_membership_interval',
+                     'mcqpi' : 'multicast_querier_interval',
+                     'mcqi' : 'multicast_query_interval',
+                     'mcqri' : 'multicast_query_response_interval',
+                     'mcsqi' : 'multicast_startup_query_interval'}
+
+        mcattrsdivby100 = ['mclmi', 'mcmi', 'mcqpi', 'mcqi', 'mcqri', 'mcsqi']
+
+        for m, s in mcattrmap.items():
+            n = self.read_file_oneline('/sys/class/net/%s/bridge/%s'
+                                    %(bridgename, s))
+            if m in mcattrsdivby100:
+                try:
+                    v = int(n) / 100
+                    mcattrs[m] = str(v)
+                except Exception, e:
+                    self.logger.warn('error getting mc attr %s (%s)'
+                                     %(m, str(e)))
+                    pass
+            else:
+                mcattrs[m] = n
+        return mcattrs
+
+    def _bridge_attrs_fill(self, bridgename):
+        battrs = {}
+        bports = {}
+
+        brout = self.exec_command('/sbin/brctl showstp %s' %bridgename)
+        chunks = re.split(r'\n\n', brout, maxsplit=0, flags=re.MULTILINE)
+
+        try:
+            # Get all bridge attributes
+            broutlines = chunks[0].splitlines()
+            #battrs['pathcost'] = broutlines[3].split('path cost')[1].strip()
+            battrs['maxage'] = broutlines[4].split(
+                                'bridge max age')[1].strip().replace('.00', '')
+            battrs['hello'] = broutlines[5].split(
+                                'bridge hello time')[1].strip().replace('.00',
+                                                                        '')
+            battrs['fd'] = broutlines[6].split(
+                                    'bridge forward delay')[1].strip(
+                                            ).replace('.00', '')
+            battrs.update(self._bridge_get_mcattrs_from_sysfs(bridgename))
+
+            # XXX: comment this out until mc attributes become available
+            # with brctl again
+            #battrs['hashel'] = broutlines[10].split('hash elasticity')[1].split()[0].strip()
+            #battrs['hashmax'] = broutlines[10].split('hash max')[1].strip()
+            #battrs['mclmc'] = broutlines[11].split('mc last member count')[1].split()[0].strip()
+            #battrs['mciqc'] = broutlines[11].split('mc init query count')[1].strip()
+            #battrs['mcrouter'] = broutlines[12].split('mc router')[1].split()[0].strip()
+            ##battrs['mcsnoop'] = broutlines[12].split('mc snooping')[1].strip()
+            #battrs['mclmt'] = broutlines[13].split('mc last member timer')[1].split()[0].strip()
+        except Exception, e:
+            self.logger.warn(str(e))
+            pass
+
+        linkCache.update_attrdict([bridgename, 'linkinfo'], battrs)
+
+        for cidx in range(1, len(chunks)):
+            bpout = chunks[cidx].lstrip('\n')
+            if not bpout or bpout[0] == ' ':
+                continue
+            bplines = bpout.splitlines()
+            pname = bplines[0].split()[0]
+            bportattrs = {}
+            try:
+                bportattrs['pathcost'] = bplines[2].split(
+                                            'path cost')[1].strip()
+                bportattrs['fdelay'] = bplines[4].split(
+                                            'forward delay timer')[1].strip()
+                bportattrs['mcrouter'] = self.read_file_oneline(
+                         '/sys/class/net/%s/brport/multicast_router' %pname)
+                bportattrs['mcfl'] = self.read_file_oneline(
+                         '/sys/class/net/%s/brport/multicast_fast_leave' %pname)
+
+                #bportattrs['mcrouters'] = bplines[6].split('mc router')[1].split()[0].strip()
+                #bportattrs['mc fast leave'] = bplines[6].split('mc fast leave')[1].strip()
+            except Exception, e:
+                self.logger.warn(str(e))
+                pass
+            bports[pname] = bportattrs
+            linkCache.update_attrdict([bridgename, 'linkinfo', 'ports'], bports)
+
+    def _bridge_fill(self, bridgename=None, refresh=False):
+        try:
+            # if cache is already filled, return
+            linkCache.get_attr([bridgename, 'linkinfo', 'fd'])
+            return
+        except:
+            pass
+        if not bridgename:
+            brctlout = self.exec_command('/sbin/brctl show')
+        else:
+            brctlout = self.exec_command('/sbin/brctl show ' + bridgename)
+        if not brctlout:
+            return
+
+        for bline in brctlout.splitlines()[1:]:
+            bitems = bline.split()
+            if len(bitems) < 2:
+                continue
+            try:
+                linkCache.update_attrdict([bitems[0], 'linkinfo'],
+                                      {'stp' : bitems[2]})
+            except KeyError:
+                linkCache.update_attrdict([bitems[0]], 
+                                {'linkinfo' : {'stp' : bitems[2]}})
+            self._bridge_attrs_fill(bitems[0])
+
+    def _cache_get(self, attrlist, refresh=False):
+        try:
+            if self.DRYRUN:
+                return None
+            if self.CACHE:
+                if not self._cache_fill_done: 
+                    self._bridge_fill()
+                    self._cache_fill_done = True
+                    return linkCache.get_attr(attrlist)
+                if not refresh:
+                    return linkCache.get_attr(attrlist)
+            self._bridge_fill(attrlist[0], refresh)
+            return linkCache.get_attr(attrlist)
+        except Exception, e:
+            self.logger.debug('_cache_get(%s) : [%s]'
+                    %(str(attrlist), str(e)))
+            pass
+        return None
+
+    def _cache_check(self, attrlist, value, refresh=False):
+        try:
+            attrvalue = self._cache_get(attrlist, refresh)
+            if attrvalue and attrvalue == value:
+                return True
+        except Exception, e:
+            self.logger.debug('_cache_check(%s) : [%s]'
+                    %(str(attrlist), str(e)))
+            pass
+        return False
+
+    def _cache_update(self, attrlist, value):
+        if self.DRYRUN: return
+        try:
+            linkCache.add_attr(attrlist, value)
+        except:
+            pass
+
+    def _cache_delete(self, attrlist):
+        if self.DRYRUN: return
+        try:
+            linkCache.del_attr(attrlist)
+        except:
+            pass
+
+    def _cache_invalidate(self):
+        if self.DRYRUN: return
+        linkCache.invalidate()
+
+    def create_bridge(self, bridgename):
+        if self.bridge_exists(bridgename):
+            return
+        self.exec_command('/sbin/brctl addbr %s' %bridgename)
+        self._cache_update([bridgename], {})
+
+    def delete_bridge(self, bridgename):
+        if not self.bridge_exists(bridgename):
+            return
+        self.exec_command('/sbin/brctl delbr %s' %bridgename)
+        self._cache_invalidate()
+
+    def add_bridge_port(self, bridgename, bridgeportname):
+        """ Add port to bridge """
+        ports = self._cache_get([bridgename, 'linkinfo', 'ports'])
+        if ports and ports.get(bridgeportname):
+            return
+        self.exec_command('/sbin/brctl addif ' + bridgename + ' ' +
+                          bridgeportname)
+        self._cache_update([bridgename, 'linkinfo', 'ports',
+                            bridgeportname], {})
+
+    def delete_bridge_port(self, bridgename, bridgeportname):
+        """ Delete port from bridge """
+        ports = self._cache_get([bridgename, 'linkinfo', 'ports'])
+        if not ports or not ports.get(bridgeportname):
+            return
+        self.exec_command('/sbin/brctl delif ' + bridgename + ' ' +
+                          bridgeportname)
+        self._cache_delete([bridgename, 'linkinfo', 'ports',
+                           'bridgeportname'])
+
+    def set_bridgeport_attrs(self, bridgename, bridgeportname, attrdict):
+        portattrs = self._cache_get([bridgename, 'linkinfo',
+                                       'ports', bridgeportname])
+        if portattrs == None: portattrs = {}
+        for k, v in attrdict.iteritems():
+            if self.CACHE:
+                curval = portattrs.get(k)
+                if curval and curval == v:
+                    continue
+            self.exec_command('/sbin/brctl set%s %s %s %s'
+                              %(k, bridgename, bridgeportname, v))
+
+    def set_bridgeport_attr(self, bridgename, bridgeportname,
+                            attrname, attrval):
+        if self._cache_check([bridgename, 'linkinfo', 'ports',
+                        bridgeportname, attrname], attrval):
+            return
+        self.exec_command('/sbin/brctl set%s %s %s %s' %(attrname, bridgename,
+                          bridgeportname, attrval))
+
+    def set_bridge_attrs(self, bridgename, attrdict):
+        for k, v in attrdict.iteritems():
+            if not v:
+                continue
+            if self._cache_check([bridgename, 'linkinfo', k], v):
+                continue
+            try:
+                self.exec_command('/sbin/brctl set%s %s %s'
+                                  %(k, bridgename, v))
+            except Exception, e:
+                self.logger.warn('%s: %s' %(bridgename, str(e)))
+                pass
+
+    def set_bridge_attr(self, bridgename, attrname, attrval):
+        if self._cache_check([bridgename, 'linkinfo', attrname], attrval):
+            return
+        self.exec_command('/sbin/brctl set%s %s %s'
+                          %(attrname, bridgename, attrval))
+
+    def get_bridge_attrs(self, bridgename):
+        return self._cache_get([bridgename, 'linkinfo'])
+
+    def get_bridgeport_attrs(self, bridgename, bridgeportname):
+        return self._cache_get([bridgename, 'linkinfo', 'ports',
+                                      bridgeportname])
+
+    def get_bridgeport_attr(self, bridgename, bridgeportname, attrname):
+        return self._cache_get([bridgename, 'linkinfo', 'ports',
+                                      bridgeportname, attrname])
+
+    def set_stp(self, bridge, stp_state):
+        self.exec_command('/sbin/brctl stp ' + bridge + ' ' + stp_state)
+
+    def get_stp(self, bridge):
+        sysfs_stpstate = '/sys/class/net/%s/bridge/stp_state' %bridge
+        if not os.path.exists(sysfs_stpstate):
+            return 'error'
+        stpstate = self.read_file_oneline(sysfs_stpstate)
+        if not stpstate:
+            return 'error'
+        try:
+            if int(stpstate) > 0:
+                return 'yes'
+            elif int(stpstate) == 0:
+                return 'no'
+        except:
+            return 'unknown'
+
+    def conv_value_to_user(self, str):
+        try:
+            ret = int(str) / 100
+        except:
+            return None
+        finally:
+            return '%d' %ret
+
+    def read_value_from_sysfs(self, filename, preprocess_func):
+        value = self.read_file_oneline(filename)
+        if not value:
+            return None
+        return preprocess_func(value)
+
+    def set_ageing(self, bridge, ageing):
+        self.exec_command('/sbin/brctl setageing ' + bridge + ' ' + ageing)
+
+    def get_ageing(self, bridge):
+        return self.read_value_from_sysfs('/sys/class/net/%s/bridge/ageing_time'
+                                     %bridge, self.conv_value_to_user)
+
+    def set_bridgeprio(self, bridge, bridgeprio):
+        self.exec_command('/sbin/brctl setbridgeprio ' + bridge + ' ' +
+                            bridgeprio)
+
+    def get_bridgeprio(self, bridge):
+        return self.read_file_oneline(
+                       '/sys/class/net/%s/bridge/priority' %bridge)
+
+    def set_fd(self, bridge, fd):
+        self.exec_command('/sbin/brctl setfd ' + bridge + ' ' + fd)
+
+    def get_fd(self, bridge):
+        return self.read_value_from_sysfs(
+                            '/sys/class/net/%s/bridge/forward_delay'
+                            %bridge, self.conv_value_to_user)
+
+    def set_gcint(self, bridge, gcint):
+        #cmd = '/sbin/brctl setgcint ' + bridge + ' ' + gcint
+        raise Exception('set_gcint not implemented')
+
+    def set_hello(self, bridge, hello):
+        self.exec_command('/sbin/brctl sethello ' + bridge + ' ' + hello)
+
+    def get_hello(self, bridge):
+        return self.read_value_from_sysfs('/sys/class/net/%s/bridge/hello_time'
+                                          %bridge, self.conv_value_to_user)
+
+    def set_maxage(self, bridge, maxage):
+        self.exec_command('/sbin/brctl setmaxage ' + bridge + ' ' + maxage)
+
+    def get_maxage(self, bridge):
+        return self.read_value_from_sysfs('/sys/class/net/%s/bridge/max_age'
+                                          %bridge, self.conv_value_to_user)
+
+    def set_pathcost(self, bridge, port, pathcost):
+        self.exec_command('/sbin/brctl setpathcost %s' %bridge + ' %s' %port +
+                            ' %s' %pathcost)
+
+    def get_pathcost(self, bridge, port):
+        return self.read_file_oneline('/sys/class/net/%s/brport/path_cost'
+                                        %port)
+
+    def set_portprio(self, bridge, port, prio):
+        self.exec_command('/sbin/brctl setportprio %s' %bridge + ' %s' %port +
+                          ' %s' %prio)
+
+    def get_portprio(self, bridge, port):
+        return self.read_file_oneline('/sys/class/net/%s/brport/priority'
+                                        %port)
+
+    def set_hashmax(self, bridge, hashmax):
+        self.exec_command('/sbin/brctl sethashmax %s' %bridge + ' %s' %hashmax)
+
+    def get_hashmax(self, bridge):
+        return self.read_file_oneline('/sys/class/net/%s/bridge/hash_max'
+                                        %bridge)
+
+    def set_hashel(self, bridge, hashel):
+        self.exec_command('/sbin/brctl sethashel %s' %bridge + ' %s' %hashel)
+
+    def get_hashel(self, bridge):
+        return self.read_file_oneline('/sys/class/net/%s/bridge/hash_elasticity'
+                                        %bridge)
+
+    def set_mclmc(self, bridge, mclmc):
+        self.exec_command('/sbin/brctl setmclmc %s' %bridge + ' %s' %mclmc)
+
+    def get_mclmc(self, bridge):
+        return self.read_file_oneline(
+                    '/sys/class/net/%s/bridge/multicast_last_member_count'
+                    %bridge)
+
+    def set_mcrouter(self, bridge, mcrouter):
+        self.exec_command('/sbin/brctl setmcrouter %s' %bridge +
+                          ' %s' %mcrouter)
+
+    def get_mcrouter(self, bridge):
+        return self.read_file_oneline(
+                    '/sys/class/net/%s/bridge/multicast_router' %bridge)
+
+    def set_mcsnoop(self, bridge, mcsnoop):
+        self.exec_command('/sbin/brctl setmcsnoop %s' %bridge +
+                          ' %s' %mcsnoop)
+
+    def get_mcsnoop(self, bridge):
+        return self.read_file_oneline(
+                    '/sys/class/net/%s/bridge/multicast_snooping' %bridge)
+
+    def set_mcsqc(self, bridge, mcsqc):
+        self.exec_command('/sbin/brctl setmcsqc %s' %bridge +
+                          ' %s' %mcsqc)
+
+    def get_mcsqc(self, bridge):
+        return self.read_file_oneline(
+                    '/sys/class/net/%s/bridge/multicast_startup_query_count'
+                    %bridge)
+
+    def set_mcqifaddr(self, bridge, mcqifaddr):
+        self.exec_command('/sbin/brctl setmcqifaddr %s' %bridge +
+                          ' %s' %mcqifaddr)
+
+    def get_mcqifaddr(self, bridge):
+        return self.read_file_oneline(
+                 '/sys/class/net/%s/bridge/multicast_startup_query_use_ifaddr'
+                 %bridge)
+
+    def set_mcquerier(self, bridge, mcquerier):
+        self.exec_command('/sbin/brctl setmcquerier %s' %bridge +
+                          ' %s' %mcquerier)
+
+    def get_mcquerier(self, bridge):
+        return self.read_file_oneline(
+                 '/sys/class/net/%s/bridge/multicast_querier' %bridge)
+
+    def set_mcqv4src(self, bridge, vlan, mcquerier):
+        if vlan == 0 or vlan > 4095:
+            self.logger.warn('mcqv4src vlan \'%d\' invalid range' %vlan)
+            return
+
+        ip = mcquerier.split('.')
+        if len(ip) != 4:
+            self.logger.warn('mcqv4src \'%s\' invalid IPv4 address' %mcquerier)
+            return
+        for k in ip:
+            if not k.isdigit() or int(k, 10) < 0 or int(k, 10) > 255:
+                self.logger.warn('mcqv4src \'%s\' invalid IPv4 address' %mcquerier)
+                return
+
+        self.exec_command('/sbin/brctl setmcqv4src %s' %bridge +
+                          ' %d %s' %(vlan, mcquerier)) 
+
+    def del_mcqv4src(self, bridge, vlan):
+        self.exec_command('/sbin/brctl delmcqv4src %s %d' %(bridge, vlan))
+
+    def get_mcqv4src(self, bridge, vlan=None):
+        mcqv4src = {}
+        mcqout = self.exec_command('/sbin/brctl showmcqv4src %s' %bridge)
+        if not mcqout: return None
+        mcqlines = mcqout.splitlines()
+        for l in mcqlines[1:]:
+            l=l.strip()
+            k, d, v = l.split('\t')
+            if not k or not v:
+                continue
+            mcqv4src[k] = v
+        if vlan:
+            return mcqv4src.get(vlan)
+        return mcqv4src
+
+    def set_mclmi(self, bridge, mclmi):
+        self.exec_command('/sbin/brctl setmclmi %s' %bridge +
+                          ' %s' %mclmi)
+
+    def get_mclmi(self, bridge):
+        return self.read_file_oneline(
+                 '/sys/class/net/%s/bridge/multicast_last_member_interval'
+                 %bridge)
+
+    def set_mcmi(self, bridge, mcmi):
+        self.exec_command('/sbin/brctl setmcmi %s' %bridge +
+                          ' %s' %mcmi)
+
+    def get_mcmi(self, bridge):
+        return self.read_file_oneline(
+                 '/sys/class/net/%s/bridge/multicast_membership_interval'
+                 %bridge)
+
+    def bridge_exists(self, bridge):
+        return os.path.exists('/sys/class/net/%s/bridge' %bridge)
+
+    def is_bridge_port(self, ifacename):
+        return os.path.exists('/sys/class/net/%s/brport' %ifacename)
+
+    def bridge_port_exists(self, bridge, bridgeportname):
+        try:
+            return os.path.exists('/sys/class/net/%s/brif/%s'
+                                  %(bridge, bridgeportname))
+        except Exception:
+            return False
+   
+    def get_bridge_ports(self, bridgename):
+        try:
+            return os.listdir('/sys/class/net/%s/brif/' %bridgename)
+        except:
+            return []
diff --git a/ifupdownaddons/cache.py b/ifupdownaddons/cache.py
new file mode 100644 (file)
index 0000000..61773b5
--- /dev/null
@@ -0,0 +1,90 @@
+#!/usr/bin/python
+#
+# Copyright 2014 Cumulus Networks, Inc. All rights reserved.
+# Author: Roopa Prabhu, roopa@cumulusnetworks.com
+#
+
+import pprint
+from collections import OrderedDict
+
+class linkCache():
+    """ This class contains methods and instance variables to cache
+    link info """
+
+    _shared_state = {}
+
+    """ { <ifacename> : { 'ifindex': <index>,
+                          'mtu': <mtu>,
+                          'state' : <state>',
+                          'flags' : <flags>,
+                          'kind' : <kind: bridge, bond, vlan>,
+                          'linkinfo' : {<attr1> : <attrval1>,
+                                        <attr2> : <attrval2>,
+                                        <ports> : {
+                                                  } """
+    links = {}
+    @classmethod
+    def get_attr(cls, mapList):
+        return reduce(lambda d, k: d[k], mapList, linkCache.links)
+
+    @classmethod
+    def set_attr(cls, mapList, value):
+        cls.get_attr(mapList[:-1])[mapList[-1]] = value
+
+    @classmethod
+    def del_attr(cls, mapList):
+        try:
+            del cls.get_attr(mapList[:-1])[mapList[-1]]
+        except:
+            pass
+
+    @classmethod
+    def update_attrdict(cls, mapList, valuedict):
+        try:
+            cls.get_attr(mapList[:-1])[mapList[-1]].update(valuedict)
+        except:
+            cls.get_attr(mapList[:-1])[mapList[-1]] = valuedict
+            pass
+
+    @classmethod
+    def append_to_attrlist(cls, mapList, value):
+        cls.get_attr(mapList[:-1])[mapList[-1]].append(value)
+
+    @classmethod
+    def remove_from_attrlist(cls, mapList, value):
+        try:
+            cls.get_attr(mapList[:-1])[mapList[-1]].remove(value)
+        except:
+            pass
+
+    @classmethod
+    def check_attr(cls, attrlist, value=None):
+        try:
+            cachedvalue = cls.get_attr(attrlist)
+            if value:
+                if cachedvalue == value:
+                    return True
+                else:
+                    return False
+            elif cachedvalue:
+                return True
+            else:
+                return False
+        except:
+            return False
+
+    @classmethod
+    def invalidate(cls):
+        cls.links = {}
+
+    @classmethod
+    def dump(cls):
+        print 'Dumping link cache'
+        pp = pprint.PrettyPrinter(indent=4)
+        pp.pprint(cls.links)
+
+    @classmethod
+    def dump_link(cls, linkname):
+        print 'Dumping link %s' %linkname
+        pp = pprint.PrettyPrinter(indent=4)
+        pp.pprint(cls.links.get(linkname))
diff --git a/ifupdownaddons/dhclient.py b/ifupdownaddons/dhclient.py
new file mode 100644 (file)
index 0000000..811ff40
--- /dev/null
@@ -0,0 +1,86 @@
+#!/usr/bin/python
+#
+# Copyright 2014 Cumulus Networks, Inc. All rights reserved.
+# Author: Roopa Prabhu, roopa@cumulusnetworks.com
+#
+
+from utilsbase import *
+import subprocess
+import os
+
+FNULL = open(os.devnull, 'w')
+
+class dhclient(utilsBase):
+    """ This class contains helper methods to interact with the dhclient
+    utility """
+
+    def _pid_exists(self, pidfilename):
+        if os.path.exists(pidfilename):
+            pid = self.read_file_oneline(pidfilename)
+            if not os.path.exists('/proc/%s' %pid):
+                return False
+        else:
+            return False
+        return True
+
+    def is_running(self, ifacename):
+        return self._pid_exists('/run/dhclient.%s.pid' %ifacename)
+
+    def is_running6(self, ifacename):
+        return self._pid_exists('/run/dhclient6.%s.pid' %ifacename)
+
+    def stop(self, ifacename):
+        if os.path.exists('/sbin/dhclient3'):
+            cmd = ['/sbin/dhclient3', '-x', '-pf',
+                   '/run/dhclient.%s.pid' %ifacename, '-lf',
+                   '/var/lib/dhcp3/dhclient.%s.leases' %ifacename,
+                   '%s' %ifacename]
+        else:
+            cmd = ['/sbin/dhclient', '-x', '-pf',
+                   '/run/dhclient.%s.pid' %ifacename,
+                   '-lf', '/var/lib/dhcp/dhclient.%s.leases' %ifacename,
+                   '%s' %ifacename]
+        self.subprocess_check_call(cmd)
+
+    def start(self, ifacename):
+        if os.path.exists('/sbin/dhclient3'):
+            cmd = ['/sbin/dhclient3', '-pf',
+                   '/run/dhclient.%s.pid' %ifacename,
+                   '-lf', '/var/lib/dhcp3/dhclient.%s.leases' %ifacename,
+                   '%s' %ifacename]
+        else:
+            cmd = ['/sbin/dhclient', '-pf', '/run/dhclient.%s.pid' %ifacename,
+                   '-lf', '/var/lib/dhcp/dhclient.%s.leases' %ifacename,
+                   '%s' %ifacename]
+        self.subprocess_check_call(cmd)
+
+    def release(self, ifacename):
+        if os.path.exists('/sbin/dhclient3'):
+            cmd = ['/sbin/dhclient3', '-r', '-pf',
+                   '/run/dhclient.%s.pid' %ifacename, '-lf',
+                   '/var/lib/dhcp3/dhclient.%s.leases' %ifacename,
+                   '%s' %ifacename]
+        else:
+            cmd = ['/sbin/dhclient', '-r', '-pf',
+                   '/run/dhclient.%s.pid' %ifacename,
+                   '-lf', '/var/lib/dhcp/dhclient.%s.leases' %ifacename,
+                   '%s' %ifacename]
+        self.subprocess_check_call(cmd)
+
+    def start6(self, ifacename):
+        self.subprocess_check_call(['dhclient', '-6', '-pf',
+                '/run/dhclient6.%s.pid' %ifacename, '-lf',
+                '/var/lib/dhcp/dhclient.%s.leases ' %ifacename,
+                '%s' %ifacename])
+
+    def stop6(self, ifacename):
+        self.subprocess_check_call(['dhclient', '-6', '-x', '-pf',
+                '/run/dhclient.%s.pid' %ifacename, '-lf',
+                '/var/lib/dhcp/dhclient.%s.leases ' %ifacename,
+                '%s' %ifacename])
+
+    def release6(self, ifacename):
+        self.subprocess_check_call(['dhclient', '-6', '-r', '-pf',
+                '/run/dhclient6.%s.pid' %ifacename, '-lf',
+                '/var/lib/dhcp/dhclient6.%s.leases' %ifacename,
+                '%s' %ifacename])
diff --git a/ifupdownaddons/ifenslaveutil.py b/ifupdownaddons/ifenslaveutil.py
new file mode 100644 (file)
index 0000000..c7e0d42
--- /dev/null
@@ -0,0 +1,421 @@
+#!/usr/bin/python
+#
+# Copyright 2014 Cumulus Networks, Inc. All rights reserved.
+# Author: Roopa Prabhu, roopa@cumulusnetworks.com
+#
+
+import os
+import re
+from ifupdown.iface import *
+from utilsbase import *
+from iproute2 import *
+from cache import *
+
+class ifenslaveutil(utilsBase):
+    """ This class contains methods to interact with linux kernel bond
+    related interfaces """
+
+    _cache_fill_done = False
+
+    def __init__(self, *args, **kargs):
+        utilsBase.__init__(self, *args, **kargs)
+        if self.CACHE and not self._cache_fill_done:
+            self._bond_linkinfo_fill_all()
+            self._cache_fill_done = True
+
+    def _bond_linkinfo_fill_attrs(self, bondname):
+        try:
+            linkCache.links[bondname]['linkinfo'] = {}
+        except:
+            linkCache.links[bondname] = {'linkinfo': {}}
+
+        try:
+            linkCache.set_attr([bondname, 'linkinfo', 'slaves'],
+                self.read_file_oneline('/sys/class/net/%s/bonding/slaves'
+                %bondname).split())
+            linkCache.set_attr([bondname, 'linkinfo', 'mode'],
+                self.read_file_oneline('/sys/class/net/%s/bonding/mode'
+                %bondname).split()[0])
+            linkCache.set_attr([bondname, 'linkinfo', 'xmit_hash_policy'],
+                self.read_file_oneline(
+                    '/sys/class/net/%s/bonding/xmit_hash_policy'
+                    %bondname).split()[0])
+            linkCache.set_attr([bondname, 'linkinfo', 'lacp_rate'],
+                self.read_file_oneline('/sys/class/net/%s/bonding/lacp_rate'
+                                       %bondname).split()[1])
+            linkCache.set_attr([bondname, 'linkinfo', 'ad_sys_priority'],
+                self.read_file_oneline('/sys/class/net/%s/bonding/ad_sys_priority'
+                                       %bondname))
+            linkCache.set_attr([bondname, 'linkinfo', 'ad_sys_mac_addr'],
+                self.read_file_oneline('/sys/class/net/%s/bonding/ad_sys_mac_addr'
+                                       %bondname))
+            map(lambda x: linkCache.set_attr([bondname, 'linkinfo', x],
+                   self.read_file_oneline('/sys/class/net/%s/bonding/%s'
+                        %(bondname, x))),
+                       ['use_carrier', 'miimon', 'min_links', 'num_unsol_na',
+                        'num_grat_arp', 'lacp_bypass_allow', 'lacp_bypass_period', 
+                        'clag_enable'])
+        except Exception, e:
+            pass
+
+    def _bond_linkinfo_fill_all(self):
+        bondstr = self.read_file_oneline('/sys/class/net/bonding_masters')
+        if not bondstr:
+            return
+        [self._bond_linkinfo_fill_attrs(b) for b in bondstr.split()]
+
+    def _bond_linkinfo_fill(self, bondname, refresh=False):
+        try:
+            linkCache.get_attr([bondname, 'linkinfo', 'slaves'])
+            return
+        except:
+            pass
+        bondstr = self.read_file_oneline('/sys/class/net/bonding_masters')
+        if (not bondstr or bondname not in bondstr.split()):
+            raise Exception('bond %s not found' %bondname)
+        self._bond_linkinfo_fill_attrs(bondname)
+
+    def _cache_get(self, attrlist, refresh=False):
+        try:
+            if self.DRYRUN:
+                return None
+            if self.CACHE:
+                if not ifenslaveutil._cache_fill_done: 
+                    self._bond_linkinfo_fill_all()
+                    ifenslaveutil._cache_fill_done = True
+                    return linkCache.get_attr(attrlist)
+                if not refresh:
+                    return linkCache.get_attr(attrlist)
+            self._bond_linkinfo_fill(attrlist[0], refresh)
+            return linkCache.get_attr(attrlist)
+        except Exception, e:
+            self.logger.debug('_cache_get(%s) : [%s]'
+                    %(str(attrlist), str(e)))
+            pass
+        return None
+
+    def _cache_check(self, attrlist, value, refresh=False):
+        try:
+            attrvalue = self._cache_get(attrlist, refresh)
+            if attrvalue and attrvalue == value:
+                return True
+        except Exception, e:
+            self.logger.debug('_cache_check(%s) : [%s]'
+                    %(str(attrlist), str(e)))
+            pass
+        return False
+
+    def _cache_update(self, attrlist, value):
+        if self.DRYRUN: return
+        try:
+            if attrlist[-1] == 'slaves':
+                linkCache.add_to_attrlist(attrlist, value)
+                return
+            linkCache.add_attr(attrlist, value)
+        except:
+            pass
+
+    def _cache_delete(self, attrlist, value=None):
+        if self.DRYRUN: return
+        try:
+            if attrlist[-1] == 'slaves':
+                linkCache.remove_from_attrlist(attrlist, value)
+                return
+            linkCache.del_attr(attrlist)
+        except:
+            pass
+
+    def _cache_invalidate(self):
+        if self.DRYRUN: return
+        linkCache.invalidate()
+
+    def set_attrs(self, bondname, attrdict, prehook):
+        for attrname, attrval in attrdict.items():
+            if (self._cache_check([bondname, 'linkinfo',
+                attrname], attrval)):
+                continue
+            if (attrname == 'mode' or attrname == 'xmit_hash_policy' or
+                    attrname == 'lacp_rate' or attrname == 'min_links'):
+                if prehook:
+                    prehook(bondname)
+            try:
+                self.write_file('/sys/class/net/%s/bonding/%s'
+                                %(bondname, attrname), attrval)
+            except Exception, e:
+                if self.FORCE:
+                    self.logger.warn(str(e))
+                    pass
+                else:
+                    raise
+
+    def set_use_carrier(self, bondname, use_carrier):
+        if not use_carrier or (use_carrier != '0' and use_carrier != '1'):
+            return
+        if (self._cache_check([bondname, 'linkinfo', 'use_carrier'],
+                use_carrier)):
+                return
+        self.write_file('/sys/class/net/%s' %bondname +
+                         '/bonding/use_carrier', use_carrier)
+        self._cache_update([bondname, 'linkinfo',
+                            'use_carrier'], use_carrier)
+
+    def get_use_carrier(self, bondname):
+        return self._cache_get([bondname, 'linkinfo', 'use_carrier'])
+
+    def set_xmit_hash_policy(self, bondname, hash_policy, prehook=None):
+        valid_values = ['layer2', 'layer3+4', 'layer2+3']
+        if not hash_policy:
+            return
+        if hash_policy not in valid_values:
+            raise Exception('invalid hash policy value %s' %hash_policy)
+        if (self._cache_check([bondname, 'linkinfo', 'xmit_hash_policy'],
+                hash_policy)):
+            return
+        if prehook:
+            prehook(bondname)
+        self.write_file('/sys/class/net/%s' %bondname +
+                         '/bonding/xmit_hash_policy', hash_policy)
+        self._cache_update([bondname, 'linkinfo', 'xmit_hash_policy'],
+                hash_policy)
+
+    def get_xmit_hash_policy(self, bondname):
+        return self._cache_get([bondname, 'linkinfo', 'xmit_hash_policy'])
+
+    def set_miimon(self, bondname, miimon):
+        if (self._cache_check([bondname, 'linkinfo', 'miimon'],
+                miimon)):
+            return
+        self.write_file('/sys/class/net/%s' %bondname +
+                '/bonding/miimon', miimon)
+        self._cache_update([bondname, 'linkinfo', 'miimon'], miimon)
+
+    def get_miimon(self, bondname):
+        return self._cache_get([bondname, 'linkinfo', 'miimon'])
+
+    def set_clag_enable(self, bondname, clag_id):
+        clag_enable = '0' if clag_id == '0' else '1'
+        if self._cache_check([bondname, 'linkinfo', 'clag_enable'], 
+                        clag_enable) == False:
+            self.write_file('/sys/class/net/%s' %bondname +
+                        '/bonding/clag_enable', clag_enable)
+            self._cache_update([bondname, 'linkinfo', 'clag_enable'], 
+                        clag_enable)
+
+    def get_clag_enable(self, bondname):
+        return self._cache_get([bondname, 'linkinfo', 'clag_enable'])
+
+    def set_mode(self, bondname, mode, prehook=None):
+        valid_modes = ['balance-rr', 'active-backup', 'balance-xor',
+                       'broadcast', '802.3ad', 'balance-tlb', 'balance-alb']
+        if not mode:
+            return
+        if mode not in valid_modes:
+            raise Exception('invalid mode %s' %mode)
+        if (self._cache_check([bondname, 'linkinfo', 'mode'],
+                mode)):
+            return
+        if prehook:
+            prehook(bondname)
+        self.write_file('/sys/class/net/%s' %bondname + '/bonding/mode', mode)
+        self._cache_update([bondname, 'linkinfo', 'mode'], mode)
+
+    def get_mode(self, bondname):
+        return self._cache_get([bondname, 'linkinfo', 'mode'])
+
+    def set_lacp_rate(self, bondname, lacp_rate, prehook=None, posthook=None):
+        if not lacp_rate or (lacp_rate != '0' and lacp_rate != '1'):
+            return
+        if (self._cache_check([bondname, 'linkinfo', 'lacp_rate'],
+                lacp_rate)):
+            return
+        if prehook:
+            prehook(bondname)
+        try:
+            self.write_file('/sys/class/net/%s' %bondname +
+                            '/bonding/lacp_rate', lacp_rate)
+        except:
+            raise
+        finally:
+            if posthook:
+                prehook(bondname)
+            self._cache_update([bondname, 'linkinfo',
+                                'lacp_rate'], lacp_rate)
+
+    def get_lacp_rate(self, bondname):
+        return self._cache_get([bondname, 'linkinfo', 'lacp_rate'])
+
+    def set_lacp_fallback_allow(self, bondname, allow, prehook=None, posthook=None):
+        if (self._cache_check([bondname, 'linkinfo', 'lacp_bypass_allow'],
+                lacp_bypass_allow)):
+            return
+        if prehook:
+            prehook(bondname)
+        try:
+            self.write_file('/sys/class/net/%s' %bondname +
+                            '/bonding/lacp_bypass_allow', allow)
+        except:
+            raise
+        finally:
+            if posthook:
+                posthook(bondname)
+            self._cache_update([bondname, 'linkinfo',
+                               'lacp_bypass_allow'], allow)
+
+    def get_lacp_fallback_allow(self, bondname):
+        return self._cache_get([bondname, 'linkinfo', 'lacp_bypass_allow'])
+
+    def set_lacp_fallback_period(self, bondname, period, prehook=None, posthook=None):
+        if (self._cache_check([bondname, 'linkinfo', 'lacp_bypass_period'],
+                lacp_bypass_period)):
+            return
+        if prehook:
+            prehook(bondname)
+        try:
+            self.write_file('/sys/class/net/%s' %bondname + 
+                            '/bonding/lacp_bypass_period', period)
+        except:
+            raise
+        finally:
+            if posthook:
+                posthook(bondname)
+            self._cache_update([bondname, 'linkinfo',
+                               'lacp_bypass_period'], period)
+
+    def get_lacp_fallback_period(self, bondname):
+        return self._cache_get([bondname, 'linkinfo', 'lacp_bypass_period']) 
+
+    def set_min_links(self, bondname, min_links, prehook=None):
+        if (self._cache_check([bondname, 'linkinfo', 'min_links'],
+                min_links)):
+            return
+        if prehook:
+            prehook(bondname)
+        self.write_file('/sys/class/net/%s/bonding/min_links' %bondname,
+                         min_links)
+        self._cache_update([bondname, 'linkinfo', 'min_links'], min_links)
+
+    def get_min_links(self, bondname):
+        return self._cache_get([bondname, 'linkinfo', 'min_links'])
+
+    def set_lacp_fallback_priority(self, bondname, port, val):
+        slavefile = '/sys/class/net/%s/bonding_slave/lacp_bypass_priority' %port
+        if os.path.exists(slavefile):
+            self.write_file(slavefile, val)
+
+    def get_lacp_fallback_priority(self, bondname):
+        slaves = self.get_slaves(bondname)
+        if not slaves:
+            return slaves
+        prios = []
+        for slave in slaves:
+            priofile = '/sys/class/net/%s/bonding_slave/lacp_bypass_priority' %slave
+            if os.path.exists(priofile):
+                val = self.read_file_oneline(priofile)
+                if val and val != '0':
+                    prio = slave + '=' + val
+                    prios.append(prio)
+        prios.sort()
+        prio_str = ' '.join(prios)
+        return prio_str
+
+    def get_ad_sys_mac_addr(self, bondname):
+        return self._cache_get([bondname, 'linkinfo', 'ad_sys_mac_addr'])
+
+    def get_ad_sys_priority(self, bondname):
+        return self._cache_get([bondname, 'linkinfo', 'ad_sys_priority'])
+
+    def enslave_slave(self, bondname, slave, prehook=None, posthook=None):
+        slaves = self._cache_get([bondname, 'linkinfo', 'slaves'])
+        if slaves and slave in slaves: return
+        if prehook:
+            prehook(slave)
+        self.write_file('/sys/class/net/%s' %bondname +
+                         '/bonding/slaves', '+' + slave)
+        if posthook:
+            posthook(slave)
+        self._cache_update([bondname, 'linkinfo', 'slaves'], slave) 
+
+    def remove_slave(self, bondname, slave):
+        slaves = self._cache_get([bondname, 'linkinfo', 'slaves'])
+        if slave not in slaves:
+            return
+        sysfs_bond_path = ('/sys/class/net/%s' %bondname +
+                           '/bonding/slaves')
+        if not os.path.exists(sysfs_bond_path):
+           return
+        self.write_file(sysfs_bond_path, '-' + slave)
+        self._cache_delete([bondname, 'linkinfo', 'slaves'], slave) 
+
+    def remove_slaves_all(self, bondname):
+        if not _self._cache_get([bondname, 'linkinfo', 'slaves']):
+            return
+        slaves = None
+        sysfs_bond_path = ('/sys/class/net/%s' %bondname +
+                           '/bonding/slaves')
+        ipcmd = iproute2()
+        try:
+            f = open(sysfs_bond_path, 'r')
+            slaves = f.readline().strip().split()
+            f.close()
+        except IOError, e:
+            raise Exception('error reading slaves of bond %s' %bondname
+                + '(' + str(e) + ')')
+        for slave in slaves:
+            ipcmd.ip_link_down(slave)
+            try:
+                self.remove_slave(bondname, slave)
+            except Exception, e:
+                if not self.FORCE:
+                    raise Exception('error removing slave %s'
+                        %slave + ' from bond %s' %bondname +
+                        '(%s)' %str(e))
+                else:
+                    pass
+        self._cache_del([bondname, 'linkinfo', 'slaves'])
+
+    def load_bonding_module(self):
+        return self.exec_command('modprobe -q bonding')
+
+    def create_bond(self, bondname):
+        if self.bond_exists(bondname):
+            return
+        sysfs_net = '/sys/class/net/'
+        sysfs_bonding_masters = sysfs_net + 'bonding_masters'
+        if not os.path.exists(sysfs_bonding_masters):
+            self.logger.debug('loading bonding driver')
+            self.load_bonding_module()
+            return True
+        self.write_file(sysfs_bonding_masters, '+' + bondname)
+        self._cache_update([bondname], {})
+
+    def delete_bond(self, bondname):
+        if not os.path.exists('/sys/class/net/%s' %bondname):
+            return
+        self.write_file('/sys/class/net/bonding_masters', '-' + bondname)
+        self._cache_delete([bondname])
+
+    def unset_master(self, bondname):
+        print 'Do nothing yet'
+        return 0
+
+    def get_slaves(self, bondname):
+        slaves = self._cache_get([bondname, 'linkinfo', 'slaves'])
+        if slaves:
+            return list(slaves)
+        slavefile = '/sys/class/net/%s/bonding/slaves' %bondname
+        if os.path.exists(slavefile):
+            buf = self.read_file_oneline(slavefile)
+            if buf:
+                slaves = buf.split()
+        if not slaves:
+            return slaves
+        self._cache_update([bondname, 'linkinfo', 'slaves'], slaves)
+        return list(slaves)
+
+    def bond_slave_exists(self, bond, slave):
+        slaves = self.get_slaves(bond)
+        if not slaves: return False
+        return slave in slaves
+
+    def bond_exists(self, bondname):
+        return os.path.exists('/sys/class/net/%s/bonding' %bondname)
diff --git a/ifupdownaddons/iproute2.py b/ifupdownaddons/iproute2.py
new file mode 100644 (file)
index 0000000..c56df83
--- /dev/null
@@ -0,0 +1,777 @@
+#!/usr/bin/python
+#
+# Copyright 2014 Cumulus Networks, Inc. All rights reserved.
+# Author: Roopa Prabhu, roopa@cumulusnetworks.com
+#
+
+import os
+from collections import OrderedDict
+from utilsbase import *
+from cache import *
+
+VXLAN_UDP_PORT = 4789
+
+class iproute2(utilsBase):
+    """ This class contains helper methods to cache and interact with the
+    commands in the iproute2 package """
+
+    _cache_fill_done = False
+    ipbatchbuf = ''
+    ipbatch = False
+    ipbatch_pause = False
+
+    def __init__(self, *args, **kargs):
+        utilsBase.__init__(self, *args, **kargs)
+        if self.CACHE and not iproute2._cache_fill_done:
+            self._link_fill()
+            self._addr_fill()
+            iproute2._cache_fill_done = True
+        
+    def _link_fill(self, ifacename=None, refresh=False):
+        """ fills cache with link information
+       
+        if ifacename argument given, fill cache for ifacename, else
+        fill cache for all interfaces in the system
+        """
+
+        linkout = {}
+        if iproute2._cache_fill_done and not refresh: return
+        try:
+            # if ifacename already present, return
+            if (ifacename and not refresh and
+                    linkCache.get_attr([ifacename, 'ifflag'])):
+                return
+        except:
+            pass
+        cmdout = self.link_show(ifacename=ifacename)
+        if not cmdout:
+            return
+        for c in cmdout.splitlines():
+            citems = c.split()
+            ifnamenlink = citems[1].split('@')
+            if len(ifnamenlink) > 1:
+                ifname = ifnamenlink[0]
+                iflink = ifnamenlink[1].strip(':')
+            else:
+                ifname = ifnamenlink[0].strip(':')
+                iflink = None
+            linkattrs = {}
+            linkattrs['link'] = iflink
+            linkattrs['ifindex'] = citems[0].strip(':')
+            flags = citems[2].strip('<>').split(',')
+            linkattrs['flags'] = flags
+            linkattrs['ifflag'] = 'UP' if 'UP' in flags else 'DOWN'
+            for i in range(0, len(citems)):
+                if citems[i] == 'mtu': linkattrs['mtu'] = citems[i+1]
+                elif citems[i] == 'state': linkattrs['state'] = citems[i+1]
+                elif citems[i] == 'link/ether': linkattrs['hwaddress'] = citems[i+1]
+                elif citems[i] == 'vlan' and citems[i+1] == 'id':
+                    linkattrs['linkinfo'] = {'vlanid' : citems[i+2]}
+                elif citems[i] == 'vxlan' and citems[i+1] == 'id':
+                    vattrs = {'vxlanid' : citems[i+2],
+                              'svcnode' : [],
+                              'remote'  : [],
+                              'ageing' : citems[i+2],
+                              'learning': 'on'}
+                    for j in range(i+2, len(citems)):
+                        if citems[j] == 'local':
+                            vattrs['local'] = citems[j+1]
+                        elif citems[j] == 'svcnode':
+                            vattrs['svcnode'].append(citems[j+1])
+                        elif citems[j] == 'peernode':
+                            vattrs['peernode'].append(citems[j+1])
+                        elif citems[j] == 'nolearning':
+                            vattrs['learning'] = 'off'
+                    # get vxlan peer nodes
+                    peers = self.get_vxlan_peers(ifname)
+                    if peers:
+                        vattrs['remote'] = peers
+                    linkattrs['linkinfo'] = vattrs
+                    break
+            #linkattrs['alias'] = self.read_file_oneline(
+            #            '/sys/class/net/%s/ifalias' %ifname)
+            linkout[ifname] = linkattrs
+        [linkCache.update_attrdict([ifname], linkattrs)
+                    for ifname, linkattrs in linkout.items()]
+
+    def _addr_filter(self, addr, scope=None):
+        default_addrs = ['127.0.0.1/8', '::1/128' , '0.0.0.0']
+        if addr in default_addrs:
+            return True
+        if scope and scope == 'link':
+            return True
+        return False
+
+    def _addr_fill(self, ifacename=None, refresh=False):
+        """ fills cache with address information
+       
+        if ifacename argument given, fill cache for ifacename, else
+        fill cache for all interfaces in the system
+        """
+
+        linkout = {}
+        if iproute2._cache_fill_done: return
+        try:
+            # Check if ifacename is already full, in which case, return
+            if ifacename:
+                linkCache.get_attr([ifacename, 'addrs']) 
+                return
+        except:
+            pass
+        cmdout = self.addr_show(ifacename=ifacename)
+        if not cmdout:
+            return
+        for c in cmdout.splitlines():
+            citems = c.split()
+            ifnamenlink = citems[1].split('@')
+            if len(ifnamenlink) > 1:
+                ifname = ifnamenlink[0]
+            else:
+                ifname = ifnamenlink[0].strip(':')
+            if citems[2] == 'inet':
+                if self._addr_filter(citems[3], scope=citems[5]):
+                    continue
+                addrattrs = {}
+                addrattrs['scope'] = citems[5]
+                addrattrs['type'] = 'inet'
+                linkout[ifname]['addrs'][citems[3]] = addrattrs
+            elif citems[2] == 'inet6':
+                if self._addr_filter(citems[3], scope=citems[5]):
+                    continue
+                if citems[5] == 'link': continue #skip 'link' addresses
+                addrattrs = {}
+                addrattrs['scope'] = citems[5]
+                addrattrs['type'] = 'inet6'
+                linkout[ifname]['addrs'][citems[3]] = addrattrs
+            else:
+                linkattrs = {}
+                linkattrs['addrs'] = OrderedDict({})
+                try:
+                    linkout[ifname].update(linkattrs)
+                except KeyError:
+                    linkout[ifname] = linkattrs
+
+        [linkCache.update_attrdict([ifname], linkattrs)
+                    for ifname, linkattrs in linkout.items()]
+
+    def _cache_get(self, type, attrlist, refresh=False):
+        try:
+            if self.DRYRUN:
+                return False
+            if self.CACHE:
+                if not iproute2._cache_fill_done: 
+                    self._link_fill()
+                    self._addr_fill()
+                    iproute2._cache_fill_done = True
+                    return linkCache.get_attr(attrlist)
+                if not refresh:
+                    return linkCache.get_attr(attrlist)
+            if type == 'link':
+                self._link_fill(attrlist[0], refresh)
+            elif type == 'addr':
+                self._addr_fill(attrlist[0], refresh)
+            else:
+                self._link_fill(attrlist[0], refresh)
+                self._addr_fill(attrlist[0], refresh)
+            return linkCache.get_attr(attrlist)
+        except Exception, e:
+            self.logger.debug('_cache_get(%s) : [%s]'
+                    %(str(attrlist), str(e)))
+            pass
+        return None
+
+    def _cache_check(self, type, attrlist, value, refresh=False):
+        try:
+            attrvalue = self._cache_get(type, attrlist, refresh)
+            if attrvalue and attrvalue == value:
+                return True
+        except Exception, e:
+            self.logger.debug('_cache_check(%s) : [%s]'
+                    %(str(attrlist), str(e)))
+            pass
+        return False
+
+    def _cache_update(self, attrlist, value):
+        if self.DRYRUN: return
+        try:
+            linkCache.add_attr(attrlist, value)
+        except:
+            pass
+
+    def _cache_delete(self, attrlist):
+        if self.DRYRUN: return
+        try:
+            linkCache.del_attr(attrlist)
+        except:
+            pass
+
+    def _cache_invalidate(self):
+        linkCache.invalidate()
+
+    def batch_start(self):
+        self.ipbatcbuf = ''
+        self.ipbatch = True
+        self.ipbatch_pause = False
+
+    def add_to_batch(self, cmd):
+        self.ipbatchbuf += cmd + '\n'
+
+    def batch_pause(self):
+        self.ipbatch_pause = True
+
+    def batch_resume(self):
+        self.ipbatch_pause = False
+
+    def batch_commit(self):
+        if not self.ipbatchbuf:
+            return
+        try:
+            self.exec_command_talk_stdin('ip -force -batch -',
+                    stdinbuf=self.ipbatchbuf)
+        except Exception:
+            raise
+        finally:
+            self.ipbatchbuf = ''
+            self.ipbatch = False
+            self.ipbatch_pause = False
+
+    def addr_show(self, ifacename=None):
+        if ifacename:
+            if not self.link_exists(ifacename):
+                return
+            return self.exec_commandl(['ip','-o', 'addr', 'show', 'dev',
+                    '%s' %ifacename])
+        else:
+            return self.exec_commandl(['ip', '-o', 'addr', 'show'])
+
+    def link_show(self, ifacename=None):
+        if ifacename:
+            return self.exec_commandl(['ip', '-o', '-d', 'link',
+                    'show', 'dev', '%s' %ifacename])
+        else:
+            return self.exec_commandl(['ip', '-o', '-d', 'link', 'show'])
+
+    def addr_add(self, ifacename, address, broadcast=None,
+                    peer=None, scope=None, preferred_lifetime=None):
+        if not address:
+            return
+        cmd = 'addr add %s' %address
+        if broadcast:
+            cmd += ' broadcast %s' %broadcast
+        if peer:
+            cmd += ' peer %s' %peer
+        if scope:
+            cmd += ' scope %s' %scope
+        if preferred_lifetime:
+            cmd += ' preferred_lft %s' %preferred_lifetime
+        cmd += ' dev %s' %ifacename
+        if self.ipbatch and not self.ipbatch_pause:
+            self.add_to_batch(cmd)
+        else:
+            self.exec_command('ip ' + cmd)
+        self._cache_update([ifacename, 'addrs', address], {})
+
+    def addr_del(self, ifacename, address, broadcast=None,
+                    peer=None, scope=None):
+        """ Delete ipv4 address """
+        if not address:
+            return
+        if not self._cache_get('addr', [ifacename, 'addrs', address]):
+            return
+        cmd = 'addr del %s' %address
+        if broadcast:
+            cmd += 'broadcast %s' %broadcast
+        if peer:
+            cmd += 'peer %s' %peer
+        if scope:
+            cmd += 'scope %s' %scope
+        cmd += ' dev %s' %ifacename
+        self.exec_command('ip ' + cmd)
+        self._cache_delete([ifacename, 'addrs', address])
+
+    def addr_flush(self, ifacename):
+        cmd = 'addr flush dev %s' %ifacename
+        if self.ipbatch and not self.ipbatch_pause:
+            self.add_to_batch(cmd)
+        else:
+            self.exec_command('ip ' + cmd)
+        self._cache_delete([ifacename, 'addrs'])
+
+    def del_addr_all(self, ifacename, skip_addrs=[]):
+        if not skip_addrs: skip_addrs = []
+        runningaddrsdict = self.addr_get(ifacename)
+        try:
+            # XXX: ignore errors. Fix this to delete secondary addresses
+            # first
+            [self.addr_del(ifacename, a) for a in
+                set(runningaddrsdict.keys()).difference(skip_addrs)]
+        except:
+            # ignore errors
+            pass
+
+    def addr_get(self, ifacename, details=True):
+        addrs = self._cache_get('addr', [ifacename, 'addrs'])
+        if not addrs:
+            return None
+        if details:
+            return addrs
+        return addrs.keys()
+
+    def addr_add_multiple(self, ifacename, addrs, purge_existing=False):
+        # purges address
+        if purge_existing:
+            # if perfmode is not set and also if iface has no sibling
+            # objects, purge addresses that are not present in the new
+            # config
+            runningaddrs = self.addr_get(ifacename, details=False)
+            if addrs == runningaddrs:
+                return
+            try:
+                # if primary address is not same, there is no need to keep any.
+                # reset all addresses
+                if (addrs and runningaddrs and
+                        (addrs[0] != runningaddrs[0])):
+                    self.del_addr_all(ifacename)
+                else:
+                    self.del_addr_all(ifacename, addrs)
+            except Exception, e:
+                self.log_warn(str(e))
+        for a in addrs:
+            try:
+                self.addr_add(ifacename, a)
+            except Exception, e:
+                self.logger.error(str(e))
+
+    def _link_set_ifflag(self, ifacename, value):
+        # Dont look at the cache, the cache may have stale value
+        # because link status can be changed by external
+        # entity (One such entity is ifupdown main program)
+        cmd = 'link set dev %s %s' %(ifacename, value.lower())
+        if self.ipbatch:
+            self.add_to_batch(cmd)
+        else:
+            self.exec_command('ip ' + cmd)
+
+    def link_up(self, ifacename):
+        self._link_set_ifflag(ifacename, 'UP')
+
+    def link_down(self, ifacename):
+        self._link_set_ifflag(ifacename, 'DOWN')
+
+    def link_set(self, ifacename, key, value=None, force=False):
+        if not force:
+            if (key not in ['master', 'nomaster'] and
+                self._cache_check('link', [ifacename, key], value)):
+                return
+        cmd = 'link set dev %s %s' %(ifacename, key)
+        if value:
+            cmd += ' %s' %value
+        if self.ipbatch:
+            self.add_to_batch(cmd)
+        else:
+            self.exec_command('ip ' + cmd)
+        if key not in ['master', 'nomaster']:
+            self._cache_update([ifacename, key], value)
+
+    def link_set_hwaddress(self, ifacename, hwaddress, force=False):
+        if not force:
+            if self._cache_check('link', [ifacename, 'hwaddress'], hwaddress):
+               return
+        self.link_down(ifacename)
+        cmd = 'link set dev %s address %s' %(ifacename, hwaddress)
+        if self.ipbatch:
+            self.add_to_batch(cmd)
+        else:
+            self.exec_command('ip ' + cmd)
+        self.link_up(ifacename)
+        self._cache_update([ifacename, 'hwaddress'], hwaddress)
+
+    def link_set_alias(self, ifacename, alias):
+        self.exec_commandl(['ip', 'link', 'set', 'dev',
+                    ifacename, 'alias', alias])
+
+    def link_get_alias(self, ifacename):
+        return self.read_file_oneline('/sys/class/net/%s/ifalias'
+                    %ifacename)
+
+    def link_isloopback(self, ifacename):
+        flags = self._cache_get('link', [ifacename, 'flags'])
+        if not flags:
+            return
+        if 'LOOPBACK' in flags:
+            return True
+        return False
+
+    def link_get_status(self, ifacename):
+        return self._cache_get('link', [ifacename, 'ifflag'], refresh=True)
+
+    def route_add_gateway(self, ifacename, gateway, metric=None):
+        if not gateway:
+           return
+        cmd = 'ip route add default via %s' %gateway
+        # Add metric
+        if metric:
+            cmd += 'metric %s' %metric
+        cmd += ' dev %s' %ifacename
+        self.exec_command(cmd)
+
+    def route_del_gateway(self, ifacename, gateway, metric=None):
+        # delete default gw
+        if not gateway:
+            return
+        cmd = 'ip route del default via %s' %gateway
+        if metric:
+            cmd += ' metric %s' %metric
+        cmd += ' dev %s' %ifacename
+        self.exec_command(cmd)
+
+    def route6_add_gateway(self, ifacename, gateway):
+        if not gateway:
+            return
+        return self.exec_command('ip -6 route add default via %s' %gateway +
+                                 ' dev %s' %ifacename)
+
+    def route6_del_gateway(self, ifacename, gateway):
+        if not gateway:
+            return
+        return self.exec_command('ip -6 route del default via %s' %gateway +
+                                 'dev %s' %ifacename)
+
+    def link_create_vlan(self, vlan_device_name, vlan_raw_device, vlanid):
+        if self.link_exists(vlan_device_name):
+            return
+        self.exec_command('ip link add link %s' %vlan_raw_device +
+                          ' name %s' %vlan_device_name +
+                          ' type vlan id %d' %vlanid)
+        self._cache_update([vlan_device_name], {})
+
+    def link_create_vlan_from_name(self, vlan_device_name):
+        v = vlan_device_name.split('.')
+        if len(v) != 2:
+            self.logger.warn('invalid vlan device name %s' %vlan_device_name)
+            return 
+        self.link_create_vlan(vlan_device_name, v[0], v[1])
+
+    def link_create_macvlan(self, name, linkdev, mode='private'):
+        if self.link_exists(name):
+            return
+        cmd = ('link add link %s' %linkdev +
+                          ' name %s' %name +
+                          ' type macvlan mode %s' %mode)
+        if self.ipbatch and not self.ipbatch_pause:
+            self.add_to_batch(cmd)
+        else:
+            self.exec_command('ip %s' %cmd)
+        self._cache_update([name], {})
+
+    def get_vxlan_peers(self, dev):
+        cmd = 'bridge fdb show brport %s' % dev
+        cur_peers = []
+        try:
+            ps = subprocess.Popen((cmd).split(), stdout=subprocess.PIPE, close_fds=True)
+            output = subprocess.check_output(('grep', '00:00:00:00:00:00'), stdin=ps.stdout)
+            ps.wait()
+            try:
+                ppat = re.compile('\s+dst\s+(\d+.\d+.\d+.\d+)\s+')
+                for l in output.split('\n'):
+                    m = ppat.search(l)
+                    if m:
+                        cur_peers.append(m.group(1))
+            except:
+                self.logger.warn('error parsing ip link output')
+                pass
+        except subprocess.CalledProcessError as e:
+            if e.returncode != 1:
+                self.logger.error(str(e))
+
+        return cur_peers
+
+    def link_create_vxlan(self, name, vxlanid,
+                          localtunnelip=None,
+                          svcnodeips=None,
+                          remoteips=None,
+                          learning='on',
+                          ageing=None):
+        if svcnodeips and remoteips:
+            raise Exception("svcnodeip and remoteip is mutually exclusive")
+        args = ''
+        if localtunnelip:
+            args += ' local %s' %localtunnelip
+        if svcnodeips:
+            for s in svcnodeips:
+                args += ' svcnode %s' %s
+        if ageing:
+            args += ' ageing %s' %ageing
+        if learning == 'off':
+            args += ' nolearning'
+
+        if self.link_exists(name):
+            cmd = 'link set dev %s type vxlan dstport %d' %(name, VXLAN_UDP_PORT)
+        else:
+            cmd = 'link add dev %s type vxlan id %s dstport %d' %(name, vxlanid, VXLAN_UDP_PORT)
+        cmd += args
+
+        if self.ipbatch and not self.ipbatch_pause:
+            self.add_to_batch(cmd)
+        else:
+            self.exec_command('ip %s' %cmd)
+
+        # figure out the diff for remotes and do the bridge fdb updates
+        cur_peers = set(self.get_vxlan_peers(name))
+        if remoteips:
+            new_peers = set(remoteips)
+            del_list = cur_peers.difference(new_peers)
+            add_list = new_peers.difference(cur_peers)
+        else:
+            del_list = cur_peers
+            add_list = []
+
+        try:
+            for addr in del_list:
+                self.bridge_fdb_del(name, '00:00:00:00:00:00', None, True, addr)
+        except:
+            pass
+
+        try:
+            for addr in add_list:
+                self.bridge_fdb_append(name, '00:00:00:00:00:00', None, True, addr)
+        except:
+            pass
+
+        # XXX: update linkinfo correctly
+        self._cache_update([name], {})
+
+    def link_exists(self, ifacename):
+        if self.DRYRUN:
+            return True
+        return os.path.exists('/sys/class/net/%s' %ifacename)
+
+    def is_vlan_device_by_name(self, ifacename):
+        if re.search(r'\.', ifacename):
+            return True
+        return False
+
+    def route_add(self, route):
+        self.exec_command('ip route add ' + route)
+
+    def route6_add(self, route):
+        self.exec_command('ip -6 route add ' + route)
+
+    def get_vlandev_attrs(self, ifacename):
+        return (self._cache_get('link', [ifacename, 'linkinfo', 'link']),
+                self._cache_get('link', [ifacename, 'linkinfo', 'vlanid']))
+
+    def get_vxlandev_attrs(self, ifacename):
+        return self._cache_get('link', [ifacename, 'linkinfo'])
+
+    def link_get_mtu(self, ifacename):
+        return self._cache_get('link', [ifacename, 'mtu'])
+
+    def link_get_hwaddress(self, ifacename):
+        address = self._cache_get('link', [ifacename, 'hwaddress'])
+        # newly created logical interface addresses dont end up in the cache
+        # read hwaddress from sysfs file for these interfaces
+        if not address:
+            address = self.read_file_oneline('/sys/class/net/%s/address'
+                                             %ifacename)
+        return address
+
+    def link_create(self, ifacename, type, link=None):
+        if self.link_exists(ifacename):
+            return
+        cmd = 'link add'
+        if link:
+            cmd += ' link %s' %link
+        cmd += ' name %s type %s' %(ifacename, type)
+        if self.ipbatch and not self.ipbatch_pause:
+            self.add_to_batch(cmd)
+        else:
+            self.exec_command('ip %s' %cmd)
+        self._cache_update([ifacename], {})
+
+    def link_delete(self, ifacename):
+        if not self.link_exists(ifacename):
+            return
+        cmd = 'link del %s' %ifacename
+        if self.ipbatch and not self.ipbatch_pause:
+            self.add_to_batch(cmd)
+        else:
+            self.exec_command('ip %s' %cmd)
+        self._cache_invalidate()
+
+    def bridge_port_vids_add(self, bridgeportname, vids):
+        [self.exec_command('bridge vlan add vid %s dev %s'
+                          %(v, bridgeportname)) for v in vids]
+
+    def bridge_port_vids_del(self, bridgeportname, vids):
+        if not vids:
+            return
+        [self.exec_command('bridge vlan del vid %s dev %s'
+                          %(v, bridgeportname)) for v in vids]
+
+    def bridge_port_vids_flush(self, bridgeportname):
+        self.exec_command('bridge vlan del vid %s dev %s'
+                          %(vid, bridgeportname))
+
+    def bridge_port_vids_get(self, bridgeportname):
+        self.exec_command('/bin/bridge vlan show %s' %bridgeportname)
+        bridgeout = self.exec_command('/bin/bridge vlan show dev %s'
+                                      %bridgeportname)
+        if not bridgeout: return []
+        brvlanlines = bridgeout.readlines()[2:]
+        vids = [l.strip() for l in brvlanlines]
+        return [vid for v in vids if vid]
+
+    def bridge_port_vids_get_all(self):
+        brvlaninfo = {}
+        bridgeout = self.exec_command('/bin/bridge vlan show')
+        if not bridgeout: return brvlaninfo
+        brvlanlines = bridgeout.splitlines()
+        brportname=None
+        for l in brvlanlines[1:]:
+            if l and l[0] not in [' ', '\t']:
+                brportname = None
+            l=l.strip()
+            if not l:
+                brportname=None
+                continue
+            if 'PVID' in l:
+                       attrs = l.split()
+                       brportname = attrs[0]
+                       brvlaninfo[brportname] = {'pvid' : attrs[1],
+                                                             'vlan' : []}
+            elif brportname:
+                if 'Egress Untagged' not in l:
+                           brvlaninfo[brportname]['vlan'].append(l)
+            elif not brportname:
+                attrs = l.split()
+                if attrs[1] == 'None' or 'Egress Untagged' in attrs[1]:
+                    continue
+                brportname = attrs[0]
+                brvlaninfo[brportname] = {'vlan' : [attrs[1]]}
+        return brvlaninfo
+
+    def bridge_port_pvid_add(self, bridgeportname, pvid):
+        self.exec_command('bridge vlan add vid %s untagged pvid dev %s'
+                          %(pvid, bridgeportname))
+
+    def bridge_port_pvid_del(self, bridgeportname, pvid):
+        self.exec_command('bridge vlan del vid %s untagged pvid dev %s'
+                          %(pvid, bridgeportname))
+
+    def bridge_port_pvids_get(self, bridgeportname):
+        return self.read_file_oneline('/sys/class/net/%s/brport/pvid'
+                                      %bridgeportname)
+
+    def bridge_vids_add(self, bridgeportname, vids, bridge=True):
+        target = 'self' if bridge else ''
+        [self.exec_command('bridge vlan add vid %s dev %s %s'
+                          %(v, bridgeportname, target)) for v in vids]
+
+    def bridge_vids_del(self, bridgeportname, vids, bridge=True):
+        target = 'self' if bridge else ''
+        [self.exec_command('bridge vlan del vid %s dev %s %s'
+                          %(v, bridgeportname, target)) for v in vids]
+
+    def bridge_fdb_add(self, dev, address, vlan=None, bridge=True, remote=None):
+        target = 'self' if bridge else ''
+        vlan_str = ''
+        if vlan:
+            vlan_str = 'vlan %s ' % vlan
+
+        dst_str = ''
+        if remote:
+            dst_str = 'dst %s ' % remote
+
+        self.exec_command('bridge fdb replace %s dev %s %s %s %s'
+                          %(address, dev, vlan_str, target, dst_str))
+
+    def bridge_fdb_append(self, dev, address, vlan=None, bridge=True, remote=None):
+        target = 'self' if bridge else ''
+        vlan_str = ''
+        if vlan:
+            vlan_str = 'vlan %s ' % vlan
+        dst_str = ''
+        if remote:
+            dst_str = 'dst %s ' % remote
+
+        self.exec_command('bridge fdb append %s dev %s %s %s %s'
+                          %(address, dev, vlan_str, target, dst_str))
+
+    def bridge_fdb_del(self, dev, address, vlan=None, bridge=True, remote=None):
+        target = 'self' if bridge else ''
+        vlan_str = ''
+        if vlan:
+            vlan_str = 'vlan %s ' % vlan
+
+        dst_str = ''
+        if remote:
+            dst_str = 'dst %s ' % remote
+        self.exec_command('bridge fdb del %s dev %s %s %s %s'
+                          %(address, dev, vlan_str, target, dst_str))
+
+    def bridge_is_vlan_aware(self, bridgename):
+        filename = '/sys/class/net/%s/bridge/vlan_filtering' %bridgename
+        if os.path.exists(filename) and self.read_file_oneline(filename) == '1':
+            return True
+        return False
+
+    def bridge_port_get_bridge_name(self, bridgeport):
+        filename = '/sys/class/net/%s/brport/bridge' %bridgeport
+        try:
+            return os.path.basename(os.readlink(filename))
+        except:
+            return None
+
+    def bridge_port_exists(self, bridge, bridgeportname):
+        try:
+            return os.path.exists('/sys/class/net/%s/brif/%s'
+                                  %(bridge, bridgeportname))
+        except Exception:
+            return False
+
+    def bridge_fdb_show_dev(self, dev):
+        try:
+            fdbs = {}
+            output = self.exec_command('bridge fdb show dev %s' %dev)
+            if output:
+                for fdb_entry in output.splitlines():
+                    try:
+                        entries = fdb_entry.split()
+                        fdbs.setdefault(entries[2], []).append(entries[0])
+                    except:
+                        self.logger.debug('%s: invalid fdb line \'%s\''
+                                %(dev, fdb_entry))
+                        pass
+            return fdbs
+        except Exception:
+            return None
+
+    def is_bridge(self, bridge):
+        return os.path.exists('/sys/class/net/%s/bridge' %bridge)
+
+    def is_link_up(self, ifacename):
+        ret = False
+        try:
+            flags = self.read_file_oneline('/sys/class/net/%s/flags' %ifacename)
+            iflags = int(flags, 16)
+            if (iflags & 0x0001):
+                ret = True
+        except: 
+            ret = False
+            pass
+        return ret
+
+    def ip_route_get_dev(self, prefix):
+        try:
+            output = self.exec_command('ip route get %s' %prefix)
+            if output:
+               rline = output.splitlines()[0]
+               if rline:
+                    rattrs = rline.split()
+                    return rattrs[rattrs.index('dev') + 1]
+        except Exception, e:
+            self.logger.debug('ip_route_get_dev: failed .. %s' %str(e))
+            pass
+        return None
diff --git a/ifupdownaddons/modulebase.py b/ifupdownaddons/modulebase.py
new file mode 100644 (file)
index 0000000..47df790
--- /dev/null
@@ -0,0 +1,363 @@
+#!/usr/bin/python
+#
+# Copyright 2014 Cumulus Networks, Inc. All rights reserved.
+# Author: Roopa Prabhu, roopa@cumulusnetworks.com
+#
+
+import os
+import re
+import io
+import logging
+import subprocess
+import traceback
+from ifupdown.iface import *
+#from ifupdownaddons.iproute2 import *
+#from ifupdownaddons.dhclient import *
+#from ifupdownaddons.bridgeutils import *
+#from ifupdownaddons.mstpctlutil import *
+#from ifupdownaddons.ifenslaveutil import *
+
+class moduleBase(object):
+    """ Base class for ifupdown addon modules
+
+    Provides common infrastructure methods for all addon modules """
+
+    def __init__(self, *args, **kargs):
+        modulename = self.__class__.__name__
+        self.logger = logging.getLogger('ifupdown.' + modulename)
+        self.FORCE = kargs.get('force', False)
+        """force interface configuration"""
+        self.DRYRUN = kargs.get('dryrun', False)
+        """only predend you are applying configuration, dont really do it"""
+        self.NOWAIT = kargs.get('nowait', False)
+        self.PERFMODE = kargs.get('perfmode', False)
+        self.CACHE = kargs.get('cache', False)
+        self.CACHE_FLAGS = kargs.get('cacheflags', 0x0)
+
+    def log_warn(self, str):
+        """ log a warning if err str is not one of which we should ignore """
+        if not self.ignore_error(str):
+            if self.logger.getEffectiveLevel() == logging.DEBUG:
+                traceback.print_stack()
+            self.logger.warn(str)
+        pass
+
+    def log_error(self, str):
+        """ log an err if err str is not one of which we should ignore and raise an exception """
+        if not self.ignore_error(str):
+            if self.logger.getEffectiveLevel() == logging.DEBUG:
+                traceback.print_stack()
+            raise Exception(str)
+        else:
+            pass
+
+    def is_process_running(self, procName):
+        try:
+            self.exec_command('/bin/pidof -x %s' % procName)
+        except:
+            return False
+        else:
+            return True
+
+    def exec_command(self, cmd, cmdenv=None):
+        """ execute command passed as argument.
+
+        Args:
+            cmd (str): command to execute
+
+        Kwargs:
+            cmdenv (dict): environment variable name value pairs
+        """
+        cmd_returncode = 0
+        cmdout = ''
+
+        try:
+            self.logger.info('Executing ' + cmd)
+            if self.DRYRUN:
+                return cmdout
+            ch = subprocess.Popen(cmd.split(),
+                    stdout=subprocess.PIPE,
+                    shell=False, env=cmdenv,
+                    stderr=subprocess.STDOUT,
+                    close_fds=True)
+            cmdout = ch.communicate()[0]
+            cmd_returncode = ch.wait()
+        except OSError, e:
+            raise Exception('could not execute ' + cmd +
+                    '(' + str(e) + ')')
+        if cmd_returncode != 0:
+            raise Exception('error executing cmd \'%s\'' %cmd +
+                '(' + cmdout.strip('\n ') + ')')
+        return cmdout
+
+    def exec_command_talk_stdin(self, cmd, stdinbuf):
+        """ execute command passed as argument and write contents of stdinbuf
+        into stdin of the cmd
+
+        Args:
+            cmd (str): command to execute
+            stdinbuf (str): string to write to stdin of the cmd process
+        """
+        cmd_returncode = 0
+        cmdout = ''
+
+        try:
+            self.logger.info('Executing %s (stdin=%s)' %(cmd, stdinbuf))
+            if self.DRYRUN:
+                return cmdout
+            ch = subprocess.Popen(cmd.split(),
+                    stdout=subprocess.PIPE,
+                    stdin=subprocess.PIPE,
+                    shell=False, env=cmdenv,
+                    stderr=subprocess.STDOUT,
+                    close_fds=True)
+            cmdout = ch.communicate(input=stdinbuf)[0]
+            cmd_returncode = ch.wait()
+        except OSError, e:
+            raise Exception('could not execute ' + cmd +
+                    '(' + str(e) + ')')
+        if cmd_returncode != 0:
+            raise Exception('error executing cmd \'%s (%s)\''
+                    %(cmd, stdinbuf) + '(' + cmdout.strip('\n ') + ')')
+        return cmdout
+
+    def get_ifaces_from_proc(self):
+        ifacenames = []
+        with open('/proc/net/dev') as f:
+            try:
+                lines = f.readlines()
+                for line in lines:
+                    ifacenames.append(line.split()[0].strip(': '))
+            except:
+                raise
+        return ifacenames
+
+    def parse_regex(self, expr, ifacenames=None):
+        try:
+            proc_ifacenames = self.get_ifaces_from_proc()
+        except:
+            self.logger.warn('error reading ifaces from proc')
+        for proc_ifacename in proc_ifacenames:
+            if re.search(expr + '$', proc_ifacename):
+                yield proc_ifacename
+        if not ifacenames:
+            return
+        for ifacename in ifacenames:
+            if re.search(expr + '$', ifacename):
+                yield ifacename
+
+    def parse_glob(self, expr):
+        errmsg = ('error parsing glob expression \'%s\'' %expr +
+                    ' (supported glob syntax: swp1-10 or swp[1-10])')
+        start_index = 0
+        end_index = 0
+        try:
+            regexs = [re.compile(r"([A-Za-z0-9\-]+[A-Za-z])(\d+)\-(\d+)(.*)"),
+                      re.compile(r"([A-Za-z0-9\-]+)\[(\d+)\-(\d+)\](.*)")]
+            for r in regexs:
+                m = r.match(expr)
+                if not m:
+                    continue
+                mlist = m.groups()
+                if len(mlist) != 4:
+                    raise Exception(errmsg + '(unexpected len)')
+                prefix = mlist[0]
+                suffix = mlist[3]
+                start_index = int(mlist[1])
+                end_index = int(mlist[2])
+        except:
+            self.logger.warn(errmsg)
+            pass
+        if not start_index and not end_index:
+            self.logger.warn(errmsg)
+            yield expr
+        else:
+            for i in range(start_index, end_index + 1):
+                yield prefix + '%d' %i + suffix
+
+    def parse_port_list(self, port_expr, ifacenames=None):
+        """ parse port list containing glob and regex
+
+        Args:
+            port_expr (str): expression
+            ifacenames (list): list of interface names. This needs to be specified if the expression has a regular expression
+        """
+        regex = 0
+        glob = 0
+        portlist = []
+
+        if not port_expr:
+            return None
+        for expr in re.split(r'[\s\t]\s*', port_expr):
+            if expr == 'noregex':
+                regex = 0
+            elif expr == 'noglob':
+                glob = 0
+            elif expr == 'regex':
+                regex = 1
+            elif expr == 'glob':
+                glob = 1
+            elif regex:
+                for port in self.parse_regex(expr, ifacenames):
+                    if port not in portlist:
+                        portlist.append(port)
+                regex = 0
+            elif glob:
+                for port in self.parse_glob(expr):
+                    portlist.append(port)
+                glob = 0
+            else:
+                portlist.append(expr)
+        if not portlist:
+            return None
+        return portlist
+
+    def ignore_error(self, errmsg):
+        if (self.FORCE or re.search(r'exists', errmsg,
+            re.IGNORECASE | re.MULTILINE)):
+            return True
+        return False
+
+    def write_file(self, filename, strexpr):
+        """ writes string to a file """
+        try:
+            self.logger.info('writing \'%s\'' %strexpr +
+                ' to file %s' %filename)
+            if self.DRYRUN:
+                return 0
+            with open(filename, 'w') as f:
+                f.write(strexpr)
+        except IOError, e:
+            self.logger.warn('error writing to file %s'
+                %filename + '(' + str(e) + ')')
+            return -1
+        return 0
+
+    def read_file(self, filename):
+        """ read file and return lines from the file """
+        try:
+            self.logger.info('reading \'%s\'' %filename)
+            with open(filename, 'r') as f:
+                return f.readlines()
+        except:
+            return None
+        return None
+
+    def read_file_oneline(self, filename):
+        """ reads and returns first line from the file """
+        try:
+            self.logger.info('reading \'%s\'' %filename)
+            with open(filename, 'r') as f:
+                return f.readline().strip('\n')
+        except:
+            return None
+        return None
+
+    def sysctl_set(self, variable, value):
+        """ set sysctl variable to value passed as argument """
+        self.exec_command('sysctl %s=' %variable + '%s' %value)
+
+    def sysctl_get(self, variable):
+        """ get value of sysctl variable """
+        return self.exec_command('sysctl %s' %variable).split('=')[1].strip()
+
+    def set_iface_attr(self, ifaceobj, attr_name, attr_valsetfunc,
+                       prehook=None, prehookargs=None):
+        ifacename = ifaceobj.name
+        attrvalue = ifaceobj.get_attr_value_first(attr_name)
+        if attrvalue:
+            if prehook:
+                if prehookargs:
+                    prehook(prehookargs)
+                else:
+                    prehook(ifacename)
+            attr_valsetfunc(ifacename, attrvalue)
+
+    def query_n_update_ifaceobjcurr_attr(self, ifaceobj, ifaceobjcurr,
+                                       attr_name, attr_valgetfunc,
+                                       attr_valgetextraarg=None):
+        attrvalue = ifaceobj.get_attr_value_first(attr_name)
+        if not attrvalue:
+            return
+        if attr_valgetextraarg:
+            runningattrvalue = attr_valgetfunc(ifaceobj.name,
+                                             attr_valgetextraarg)
+        else:
+            runningattrvalue = attr_valgetfunc(ifaceobj.name)
+        if (not runningattrvalue or
+            (runningattrvalue != attrvalue)):
+            ifaceobjcurr.update_config_with_status(attr_name,
+                runningattrvalue, 1)
+        else:
+            ifaceobjcurr.update_config_with_status(attr_name,
+                runningattrvalue, 0)
+
+    def dict_key_subset(self, a, b): 
+        """ returns a list of differing keys """
+        return [x for x in a if x in b]
+
+    def get_mod_attrs(self):
+        """ returns list of all module attrs defined in the module _modinfo dict"""
+        try:
+            return self._modinfo.get('attrs').keys()
+        except:
+            return None
+
+    def get_mod_attr(self, attrname):
+        """ returns module attr info """
+        try:
+            return self._modinfo.get('attrs', {}).get(attrname)
+        except:
+            return None
+
+    def get_mod_subattr(self, attrname, subattrname):
+        """ returns module attrs defined in the module _modinfo dict"""
+        try:
+            return reduce(lambda d, k: d[k], ['attrs', attrname, subattrname],
+                         self._modinfo)
+        except:
+            return None
+
+    def get_modinfo(self):
+        """ return module info """
+        try:
+            return self._modinfo
+        except:
+            return None
+
+    def get_flags(self):
+        return dict(force=self.FORCE, dryrun=self.DRYRUN, nowait=self.NOWAIT,
+                    perfmode=self.PERFMODE, cache=self.CACHE,
+                    cacheflags=self.CACHE_FLAGS)
+
+    def _get_reserved_vlan_range(self):
+        start = end = 0
+        get_resvvlan = '/usr/share/python-ifupdown2/get_reserved_vlan_range.sh'
+        if not os.path.exists(get_resvvlan):
+            return (start, end)
+        try:
+            (s, e) = self.exec_command(get_resvvlan).strip('\n').split('-')
+            start = int(s)
+            end = int(e)
+        except Exception, e:
+            self.logger.debug('%s failed (%s)' %(get_resvvlan, str(e)))
+            # ignore errors
+            pass
+        return (start, end)
+
+    def _handle_reserved_vlan(self, vlanid, logprefix=''):
+        """ Helper function to check and warn if the vlanid falls in the
+        reserved vlan range """
+        if vlanid in range(self._resv_vlan_range[0],
+                           self._resv_vlan_range[1]):
+           self.logger.error('%s: reserved vlan %d being used'
+                   %(logprefix, vlanid) + ' (reserved vlan range %d-%d)'
+                   %(self._resv_vlan_range[0], self._resv_vlan_range[1]))
+           return True
+        return False
+
+    def _valid_ethaddr(self, ethaddr):
+        """ Check if address is 00:00:00:00:00:00 """
+        if not ethaddr or re.match('00:00:00:00:00:00', ethaddr):
+            return False
+        return True
diff --git a/ifupdownaddons/mstpctlutil.py b/ifupdownaddons/mstpctlutil.py
new file mode 100644 (file)
index 0000000..4716195
--- /dev/null
@@ -0,0 +1,171 @@
+#!/usr/bin/python
+#
+# Copyright 2014 Cumulus Networks, Inc. All rights reserved.
+# Author: Roopa Prabhu, roopa@cumulusnetworks.com
+#
+
+from utilsbase import *
+from ifupdown.iface import *
+from cache import *
+import re
+
+class mstpctlutil(utilsBase):
+    """ This class contains helper methods to interact with mstpd using
+    mstputils commands """
+
+    _cache_fill_done = False
+
+    _bridgeattrmap = {'bridgeid' : 'bridge-id',
+                     'maxage' : 'max-age',
+                     'fdelay' : 'forward-delay',
+                     'txholdcount' : 'tx-hold-count',
+                     'maxhops' : 'max-hops',
+                     'ageing' : 'ageing-time',
+                     'hello' : 'hello-time',
+                     'forcevers' : 'force-protocol-version'}
+
+    _bridgeportattrmap = {'portadminedge' : 'admin-edge-port',
+                     'portp2p' : 'admin-point-to-point',
+                     'portrestrrole' : 'restricted-role',
+                     'portrestrtcn' : 'restricted-TCN',
+                     'bpduguard' : 'bpdu-guard-port',
+                     'portautoedge' : 'auto-edge-port',
+                     'portnetwork' : 'network-port',
+                     'portbpdufilter' : 'bpdufilter-port'}
+
+    def __init__(self, *args, **kargs):
+        utilsBase.__init__(self, *args, **kargs)
+
+    def is_mstpd_running(self):
+        try:
+            self.exec_command('/bin/pidof mstpd')
+        except:
+            return False
+        else:
+            return True
+
+    def get_bridgeport_attr(self, bridgename, portname, attrname):
+        try:
+            return self.subprocess_check_output(['/sbin/mstpctl',
+                       'showportdetail', '%s' %bridgename, '%s' %portname,
+                       self._bridgeportattrmap[attrname]]).strip('\n')
+        except Exception, e:
+            pass
+        return None
+
+    def get_bridgeport_attrs(self, bridgename, portname):
+        bridgeattrs = {}
+        try:
+            bridgeattrs = dict((k, self.get_bridgeport_attr(bridgename, v))
+                                 for k, v in self._bridgeattrmap.items())
+            bridgeattrs['treeprio'] = int(bridgeattrs.get('bridgeid',
+                                     '').split('.')[0], base=16) * 4096
+        except Exception, e:
+            self.logger.warn(str(e))
+            pass
+        return bridgeattrs
+
+    def set_bridgeport_attrs(self, bridgename, bridgeportname, attrdict,
+                             check=True):
+        for k, v in attrdict.iteritems():
+            if not v:
+                continue
+            try:
+                self.set_bridgeport_attr(self, bridgename, bridgeportname,
+                        k, v, check)
+            except Exception, e:
+                self.logger.warn(str(e))
+
+    def set_bridgeport_attr(self, bridgename, bridgeportname, attrname,
+                            attrvalue, check=True):
+        if check:
+            attrvalue_curr = self.get_bridgeport_attr(bridgename,
+                                    bridgeportname, attrname)
+            if attrvalue_curr and attrvalue_curr == attrvalue:
+                return
+        if attrname == 'treeportcost' or attrname == 'treeportprio':
+            self.subprocess_check_output(['/sbin/mstpctl', 'set%s' %attrname,
+                  '%s' %bridgename, '%s' %bridgeportname, '0', '%s' %attrvalue])
+        else:
+            self.subprocess_check_output(['/sbin/mstpctl', 'set%s' %attrname,
+                  '%s' %bridgename, '%s' %bridgeportname, '%s' %attrvalue])
+
+    def get_bridge_attrs(self, bridgename):
+        bridgeattrs = {}
+        try:
+            bridgeattrs = dict((k, self.get_bridge_attr(bridgename, k))
+                                 for k in self._bridgeattrmap.keys())
+            bridgeattrs['treeprio'] = '%d' %(int(bridgeattrs.get('bridgeid',
+                                     '').split('.')[0], base=16) * 4096)
+            del bridgeattrs['bridgeid']
+        except Exception, e:
+            self.logger.debug(bridgeattrs)
+            self.logger.debug(str(e))
+            pass
+        return bridgeattrs
+
+    def get_bridge_attr(self, bridgename, attrname):
+        try:
+            return self.subprocess_check_output(['/sbin/mstpctl',
+                       'showbridge', '%s' %bridgename,
+                       self._bridgeattrmap[attrname]]).strip('\n')
+        except Exception, e:
+            pass
+        return None
+
+    def set_bridge_attr(self, bridgename, attrname, attrvalue, check=True):
+
+        if check:
+            attrvalue_curr = self.get_bridge_attr(bridgename, attrname)
+            if attrvalue_curr and attrvalue_curr == attrvalue:
+                return
+        if attrname == 'treeprio':
+            self.subprocess_check_call(['/sbin/mstpctl', 'set%s' %attrname,
+                        '%s' %bridgename, '0',  '%s' %attrvalue])
+        else:
+            self.subprocess_check_call(['/sbin/mstpctl', 'set%s' %attrname,
+                        '%s' %bridgename, '%s' %attrvalue])
+
+    def set_bridge_attrs(self, bridgename, attrdict, check=True):
+        for k, v in attrdict.iteritems():
+            if not v:
+                continue
+            try:
+                self.set_bridge_attr(bridgename, k, v, check)
+            except Exception, e:
+                self.logger.warn('%s: %s' %(bridgename, str(e)))
+                pass
+
+    def get_bridge_treeprio(self, bridgename):
+        try:
+            bridgeid = subprocess.check_output(['/sbin/mstpctl',
+                       'showbridge', '%s' %bridgename,
+                       self._bridgeattrmap['bridgeid']]).strip('\n')
+            return '%d' %(int(bridgeid.split('.')[0], base=16) * 4096)
+        except:
+            pass
+        return None
+
+    def set_bridge_treeprio(self, bridgename, attrvalue, check=True):
+        if check:
+            attrvalue_curr = self.get_bridge_treeprio(bridgename)
+            if attrvalue_curr and attrvalue_curr == attrvalue:
+                return
+        self.subprocess_check_output(['/sbin/mstpctl', 'settreeprio',
+                        '%s' %bridgename, '0',  '%s' %attrvalue])
+
+    def showbridge(self, bridgename=None):
+        if bridgename:
+            return self.exec_command('/sbin/mstpctl showbridge %s' %bridgename)
+        else:
+            return self.exec_command('/sbin/mstpctl showbridge')
+
+    def showportdetail(self, bridgename):
+        return self.exec_command('/sbin/mstpctl showportdetail %s' %bridgename)
+
+    def mstpbridge_exists(self, bridgename):
+        try:
+            subprocess.check_call('mstpctl showbridge %s' %bridgename)
+            return True
+        except:
+            return False
diff --git a/ifupdownaddons/utilsbase.py b/ifupdownaddons/utilsbase.py
new file mode 100644 (file)
index 0000000..73fdfd5
--- /dev/null
@@ -0,0 +1,163 @@
+#!/usr/bin/python
+#
+# Copyright 2014 Cumulus Networks, Inc. All rights reserved.
+# Author: Roopa Prabhu, roopa@cumulusnetworks.com
+#
+
+import logging
+import subprocess
+import re
+import io
+from ifupdown.iface import *
+from cache import *
+
+#import timeit
+import time
+import logging
+
+def profile(func):
+    def wrap(*args, **kwargs):
+        started_at = time.time()
+        result = func(*args, **kwargs)
+        print str(func)
+        print (time.time() - started_at)
+        return result
+    return wrap
+
+class utilsBase(object):
+    """ Base class for ifupdown addon utilities """
+
+    def __init__(self, *args, **kargs):
+        modulename = self.__class__.__name__
+        self.logger = logging.getLogger('ifupdown.' + modulename)
+        self.FORCE = kargs.get('force', False)
+        self.DRYRUN = kargs.get('dryrun', False)
+        self.NOWAIT = kargs.get('nowait', False)
+        self.PERFMODE = kargs.get('perfmode', False)
+        self.CACHE = kargs.get('cache', False)
+
+    def exec_commandl(self, cmdl, cmdenv=None):
+        """ Executes command """
+
+        cmd_returncode = 0
+        cmdout = ''
+        try:
+            self.logger.info('executing ' + ' '.join(cmdl))
+            if self.DRYRUN:
+                return cmdout
+            ch = subprocess.Popen(cmdl,
+                    stdout=subprocess.PIPE,
+                    shell=False, env=cmdenv,
+                    stderr=subprocess.STDOUT,
+                    close_fds=True)
+            cmdout = ch.communicate()[0]
+            cmd_returncode = ch.wait()
+        except OSError, e:
+            raise Exception('failed to execute cmd \'%s\' (%s)'
+                            %(' '.join(cmdl), str(e)))
+        if cmd_returncode != 0:
+            raise Exception('failed to execute cmd \'%s\''
+                 %' '.join(cmdl) + '(' + cmdout.strip('\n ') + ')')
+        return cmdout
+
+    def exec_command(self, cmd, cmdenv=None):
+        """ Executes command given as string in the argument cmd """
+
+        return self.exec_commandl(cmd.split(), cmdenv)
+
+    def exec_command_talk_stdin(self, cmd, stdinbuf):
+        """ Executes command and writes to stdin of the process """
+        cmd_returncode = 0
+        cmdout = ''
+        try:
+            self.logger.info('executing %s [%s]' %(cmd, stdinbuf))
+            if self.DRYRUN:
+                return cmdout
+            ch = subprocess.Popen(cmd.split(),
+                    stdout=subprocess.PIPE,
+                    stdin=subprocess.PIPE,
+                    shell=False,
+                    stderr=subprocess.STDOUT,
+                    close_fds=True)
+            cmdout = ch.communicate(input=stdinbuf)[0]
+            cmd_returncode = ch.wait()
+        except OSError, e:
+            raise Exception('failed to execute cmd \'%s\' (%s)'
+                            %(cmd, str(e)))
+        if cmd_returncode != 0:
+            raise Exception('failed to execute cmd \'%s [%s]\''
+                %(cmd, stdinbuf) + '(' + cmdout.strip('\n ') + ')')
+        return cmdout
+
+    def subprocess_check_output(self, cmdl):
+        self.logger.info('executing ' + ' '.join(cmdl))
+        if self.DRYRUN:
+            return
+        try:
+            return subprocess.check_output(cmdl, stderr=subprocess.STDOUT)
+        except Exception, e:
+            raise Exception('failed to execute cmd \'%s\' (%s)'
+                        %(' '.join(cmdl), e.output))
+
+    def subprocess_check_call(self, cmdl):
+        """ subprocess check_call implementation using popen
+        
+        Uses popen because it needs the close_fds argument
+        """
+
+        cmd_returncode = 0
+        try:
+            self.logger.info('executing ' + ' '.join(cmdl))
+            if self.DRYRUN:
+                return
+            ch = subprocess.Popen(cmdl,
+                    stdout=None,
+                    shell=False,
+                    stderr=None,
+                    close_fds=True)
+            cmd_returncode = ch.wait()
+        except Exception, e:
+            raise Exception('failed to execute cmd \'%s\' (%s)'
+                            %(' '.join(cmdl), str(e)))
+        if cmd_returncode != 0:
+            raise Exception('failed to execute cmd \'%s\''
+                 %' '.join(cmdl))
+        return
+
+    def write_file(self, filename, strexpr):
+        try:
+            self.logger.info('writing \'%s\'' %strexpr +
+                ' to file %s' %filename)
+            if self.DRYRUN:
+                return 0
+            with open(filename, 'w') as f:
+                f.write(strexpr)
+        except IOError, e:
+            self.logger.warn('error writing to file %s'
+                %filename + '(' + str(e) + ')')
+            return -1
+        return 0
+
+    def read_file(self, filename):
+        try:
+            self.logger.debug('reading \'%s\'' %filename)
+            with open(filename, 'r') as f:
+                return f.readlines()
+        except:
+            return None
+        return None
+
+    def read_file_oneline(self, filename):
+        try:
+            self.logger.debug('reading \'%s\'' %filename)
+            with open(filename, 'r') as f:
+                return f.readline().strip('\n')
+        except:
+            return None
+        return None
+
+    def sysctl_set(self, variable, value):
+        self.exec_command('sysctl %s=' %variable + '%s' %value)
+
+    def sysctl_get(self, variable):
+        return self.exec_command('sysctl %s' %variable).split('=')[1].strip()
diff --git a/init.d/networking b/init.d/networking
new file mode 100644 (file)
index 0000000..45d3d78
--- /dev/null
@@ -0,0 +1,218 @@
+#!/bin/bash
+### BEGIN INIT INFO
+# Provides:          networking ifupdown
+# Required-Start:    mountkernfs $local_fs urandom
+# Required-Stop:     $local_fs
+# Default-Start:     S
+# Default-Stop:      0 6
+# Short-Description: Raise network interfaces.
+# Description:       Prepare /run/network directory, ifstate file and raise network interfaces, or take them down.
+### END INIT INFO
+
+PATH="/sbin:/bin"
+RUN_DIR="/run/network"
+IFSTATE="$RUN_DIR/ifstate"
+
+NAME=networking
+SCRIPTNAME=/etc/init.d/$NAME
+
+[ -x /sbin/ifup ] || exit 0
+[ -x /sbin/ifdown ] || exit 0
+
+. /lib/lsb/init-functions
+
+CONFIGURE_INTERFACES=yes
+
+EXTRA_ARGS=
+
+[ -f /etc/default/networking ] && . /etc/default/networking
+
+[ "$VERBOSE" = yes ] && EXTRA_ARGS=-v
+[ "$DEBUG" = yes ] && EXTRA_ARGS="$EXTRA_ARGS -d"
+[ "$SYSLOG" = yes ] && EXTRA_ARGS="$EXTRA_ARGS --syslog"
+
+gen_examples() {
+    # Generate sample interfaces file. The interfaces files are
+    # generated under /usr/share/doc/python-ifupdown2/examples/
+    #
+
+    # generate files only at boot
+    [ -f /var/tmp/network/ifstatenew ] && return
+
+    python_ifupdown2_docdir="/usr/share/doc/python-ifupdown2"
+    swpfile=${python_ifupdown2_docdir}"/examples/swp_defaults"
+    bridgedefaultfile=${python_ifupdown2_docdir}"/examples/bridge_untagged_default"
+    interfaces_gen_script=${python_ifupdown2_docdir}"/examples/generate_interfaces.py"
+
+    [ ! -e $interfaces_gen_script ] && return
+    ret=$($interfaces_gen_script -s 2>&1 >$swpfile)
+    ret=$($interfaces_gen_script -b 2>&1 >$bridgedefaultfile)
+    return
+}
+
+perf_options() {
+    # At bootup lets set perfmode
+    [ -f /var/tmp/network/ifstatenew ] && echo -n "" && return
+
+    echo -n "--perfmode"
+}
+
+process_exclusions() {
+    set -- $EXCLUDE_INTERFACES
+    exclusions=""
+    for d
+    do
+       exclusions="-X $d $exclusions"
+    done
+    echo $exclusions
+}
+
+check_network_file_systems() {
+    [ -e /proc/mounts ] || return 0
+
+    if [ -e /etc/iscsi/iscsi.initramfs ]; then
+       log_warning_msg "not deconfiguring network interfaces: iSCSI root is mounted."
+       exit 0
+    fi
+
+    while read DEV MTPT FSTYPE REST; do
+       case $DEV in
+       /dev/nbd*|/dev/nd[a-z]*|/dev/etherd/e*)
+           log_warning_msg "not deconfiguring network interfaces: network devices still mounted."
+           exit 0
+           ;;
+       esac
+       case $FSTYPE in
+       nfs|nfs4|smbfs|ncp|ncpfs|cifs|coda|ocfs2|gfs|pvfs|pvfs2|fuse.httpfs|fuse.curlftpfs)
+           log_warning_msg "not deconfiguring network interfaces: network file systems still mounted."
+           exit 0
+           ;;
+       esac
+    done < /proc/mounts
+}
+
+check_network_swap() {
+    [ -e /proc/swaps ] || return 0
+
+    while read DEV MTPT FSTYPE REST; do
+       case $DEV in
+       /dev/nbd*|/dev/nd[a-z]*|/dev/etherd/e*)
+           log_warning_msg "not deconfiguring network interfaces: network swap still mounted."
+           exit 0
+           ;;
+       esac
+    done < /proc/swaps
+}
+
+ifup_hotplug () {
+    if [ -d /sys/class/net ]
+    then
+           ifaces=$(for iface in $(ifquery --list --allow=hotplug 2>/dev/null)
+                           do
+                                   link=${iface##:*}
+                                   link=${link##.*}
+                                   if [ -e "/sys/class/net/$link" ] && [ "$(cat /sys/class/net/$link/operstate)" = up ]
+                                   then
+                                           echo "$iface"
+                                   fi
+                           done)
+           if [ -n "$ifaces" ]
+           then
+               ifup $ifaces "$@" || true
+           fi
+    fi
+}
+
+ifupdown_init() {
+       [ ! -e /run/network ] && mkdir -p /run/network &>/dev/null
+       [ ! -e /etc/network/run ] && \
+               ln -sf /run/network /etc/network/run &>/dev/null
+}
+
+case "$1" in
+start)
+       gen_examples
+       ifupdown_init
+       if [ "$CONFIGURE_INTERFACES" = no ]
+       then
+           log_action_msg "Not configuring network interfaces, see /etc/default/networking"
+           exit 0
+       fi
+       set -f
+       exclusions=$(process_exclusions)
+       perfoptions=$(perf_options)
+       log_action_begin_msg "Configuring network interfaces"
+       ifup -a $EXTRA_ARGS $exclusions $perfoptions 
+       log_action_end_msg $?
+       ;;
+
+stop)
+       if [ "$SKIP_DOWN_AT_SYSRESET" = "yes" ]; then
+               shutdown_or_reboot=$(runlevel 2>/dev/null | \
+                                    /usr/bin/tr -s " " | \
+                                    /usr/bin/cut -d " " \
+                                    -f1- --output-delimiter=$'\n' | \
+                                    /bin/grep -e "0" -e "6")
+               if [ -n "$shutdown_or_reboot" ]; then
+                       log_action_begin_msg "Deconfiguring network interfaces..skip"
+                       log_action_end_msg 0
+                       exit 0
+               fi
+       fi
+       ifupdown_init
+       check_network_file_systems
+       check_network_swap
+       exclusions=$(process_exclusions)
+
+       log_action_begin_msg "Deconfiguring network interfaces"
+       ifdown -a $EXTRA_ARGS $exclusions
+       log_action_end_msg $?
+       ;;
+
+reload)
+
+       ifupdown_init
+       log_action_begin_msg "Reloading network interfaces configuration"
+
+       ifreload -a $EXTRA_ARGS
+       log_action_end_msg $?
+       ;;
+
+reload-currently-up)
+
+       ifupdown_init
+       log_action_begin_msg "Reloading currently up network interfaces configuration"
+
+       ifreload --currently-up $EXTRA_ARGS
+       log_action_end_msg $?
+       ;;
+
+force-reload)
+
+       ifupdown_init
+
+       log_action_begin_msg "Reloading network interfaces configuration"
+       ifreload -f -a $EXTRA_ARGS
+       log_action_end_msg $?
+       ;;
+
+restart)
+       ifupdown_init
+
+       set -f
+       exclusions=$(process_exclusions)
+       log_action_begin_msg "Reconfiguring network interfaces"
+       ifdown -a $EXTRA_ARGS $exclusions || true
+       ifup -a $EXTRA_ARGS $exclusions
+       log_action_end_msg $?
+       ;;
+
+*)
+       echo "Usage: /etc/init.d/networking {start|stop|reload|restart|force-reload}"
+       exit 1
+       ;;
+esac
+
+exit 0
+
+# vim: noet ts=8
diff --git a/man.rst/ifquery.8.rst b/man.rst/ifquery.8.rst
new file mode 100644 (file)
index 0000000..ba443ce
--- /dev/null
@@ -0,0 +1,151 @@
+=======
+ifquery
+=======
+
+-------------------------------------
+query network interface configuration
+-------------------------------------
+
+:Author: Roopa Prabhu <roopa@cumulusnetworks.com>
+:Date:   2014-02-05
+:Copyright: Copyright 2014 Cumulus Networks, Inc.  All rights reserved.
+:Version: 0.1
+:Manual section: 8
+
+SYNOPSIS
+========
+
+    **ifquery [-v] [--allow CLASS] [--with-depends] -a|IFACE...**
+
+    **ifquery [-v] [-r|--running] [--allow CLASS] [--with-depends] -a|IFACE...**
+
+    **ifquery [-v] [-c|--check] [--allow CLASS] [--with-depends] -a|IFACE...**
+
+    **ifquery [-v] [-p|--print-dependency {list,dot}] [--allow CLASS] [--with-depends] -a|IFACE...**
+
+    **ifquery [-v] -s|--syntax-help**
+
+DESCRIPTION
+===========
+    **ifquery** can be used to parse interface configuration file, query
+    running state or check running state of the interface with configuration
+    in **/etc/network/interfaces** file.
+
+    **ifquery** always works on the current **interfaces(5)** file
+    **/etc/network/interfaces** unless an alternate interfaces file is
+    provided with the **-i** option.
+
+OPTIONS
+=======
+    positional arguments:
+
+    **IFACE**   interface list separated by spaces. **IFACE** list and **'-a'** argument are mutually exclusive.
+
+    optional arguments:
+
+    -h, --help            show this help message and exit
+
+    -a, --all             process all interfaces marked "auto"
+
+    -v, --verbose         verbose
+
+    -d, --debug           output debug info
+    --allow CLASS         ignore non-"allow-CLASS" interfaces
+
+    -w, --with-depends    run with all dependent interfaces. This option
+                          is redundant when -a is specified. When '-a' is
+                          specified, interfaces are always executed in
+                          dependency order.
+
+    -X EXCLUDEPATS, --exclude EXCLUDEPATS
+                          Exclude interfaces from the list of interfaces to
+                          operate on. Can be specified multiple times
+
+    -i INTERFACESFILE, --interfaces INTERFACESFILE
+                          Use interfaces file instead of default
+                          /etc/network/interfaces
+
+    -t {native,json}, --interfaces-format {native,json}
+                          interfaces file format
+
+    -r, --running         print raw interfaces file entries
+
+    -c, --check           check interface file contents against running state
+                          of an interface. Returns exit code 0 on success and
+                          1 on error
+
+    -x, --raw             print raw config file entries
+
+    -o {native,json}, --format {native,json}
+                          interface display format
+
+    -p, --print-dependency {list,dot}
+                          print iface dependency in list or dot format
+
+    -s, --syntax-help     print supported interface config syntax. Scans all
+                          addon modules and dumps supported syntax from them
+                          if provided by the module.
+
+EXAMPLES
+========
+    # dump all or some interfaces config file entries
+    # (pretty prints user provided entries)
+
+        **ifquery -a**
+
+        **ifquery br0**
+
+    # Same as above but dump with dependencies
+
+        **ifquery br0 --with-depends**
+
+    # Check running state with the config in /etc/network/interfaces
+
+        **ifquery --check br0**
+
+        **ifquery --check --with-depends br0**
+
+        **ifquery --check -a** 
+
+    # dump running state of all interfaces in /etc/network/interfaces format
+
+        **ifquery --running br0**
+
+        **ifquery --running --with-depends br0**
+
+        **ifquery --running -a**
+
+    # print dependency info in list format
+
+        **ifquery --print-dependency=list -a**
+
+        **ifquery --print-dependency=list  br2000**
+
+    # print dependency info in dot format
+
+        **ifquery --print-dependency=dot -a**
+
+        **ifquery --print-dependency=dot br2000**
+
+    # Create an image (png) from the dot format
+
+        **ifquery --print-dependency=dot -a > interfaces.dot**
+
+        **dot -Tpng interfaces.dot > interfaces.png**
+
+        (The above command only works on a system with dot installed)
+
+KNOWN_ISSUES
+============
+    **ifquery --check** is currently experimental
+
+    **ifquery --check** cannot validate usercommands given under pre-up, post-up etc
+    There is currently no support to check/validate ethtool iface attributes
+
+SEE ALSO
+========
+    ifup(8),
+    ifdown(8),
+    ifreload(8),
+    interfaces(5),
+    ifupdown-addons-interfaces(5)
diff --git a/man.rst/ifreload.8.rst b/man.rst/ifreload.8.rst
new file mode 100644 (file)
index 0000000..f26442b
--- /dev/null
@@ -0,0 +1,80 @@
+========
+ifreload
+========
+
+--------------------------------------
+reload network interface configuration
+--------------------------------------
+
+:Author: Roopa Prabhu <roopa@cumulusnetworks.com>
+:Date:   2014-02-05
+:Copyright: Copyright 2014 Cumulus Networks, Inc.  All rights reserved.
+:Version: 0.1
+:Manual section: 8
+
+SYNOPSIS
+========
+    ifreload [-h] (-a|-c) [-v] [-d] [-f] [-n] 
+
+DESCRIPTION
+===========
+    reloads network **interfaces(5)** file **/etc/network/interfaces**.
+
+    Runs **ifdown** on interfaces that were removed from the file and
+    subsequently runs **ifup** on all interfaces.
+
+    When removing an interface (iface section) from the interfaces file
+    please make sure all its references are removed as well. Similarly
+    when renaming an interface, please make sure all references to the
+    interface are changed to the new name. Renaming an interface
+    in the interfaces file results in ifdown of the old and ifup
+    of the interface with the new name.
+
+    If you do not wish to execute **down** on any interfaces, but only **up** on
+    interfaces that were already **up**, please see the **--currently-up**
+    option below.
+
+
+OPTIONS
+=======
+    -h, --help            show this help message and exit
+
+    -a, --all             process all interfaces marked "auto"
+
+    -v, --verbose         verbose
+
+    -d, --debug           output debug info
+
+    -f, --force           force run all operations
+
+    -c, --currently-up    only reload auto and other interfaces that are
+                          currently up. This can be used as a non-disruptive
+                          alternative to -a because it will not down any
+                          interfaces
+
+    -X EXCLUDEPATS, --exclude EXCLUDEPATS
+                          Exclude interfaces from the list of interfaces to
+                          operate on. Can be specified multiple times
+
+
+EXAMPLES
+========
+    # reload all auto interfaces in **interfaces(5)** file
+
+    **ifreload -a**
+
+    # reload all interfaces using service command
+
+    **service networking reload**
+
+    # reload all currently up interfaces without bringing any interfaces down
+
+    **service networking reload-currently-up**
+
+SEE ALSO
+========
+    ifup(8),
+    ifdown(8),
+    ifquery(8),
+    interfaces(5),
+    ifupdown-addons-interfaces(5)
diff --git a/man.rst/ifup.8.rst b/man.rst/ifup.8.rst
new file mode 100644 (file)
index 0000000..407b44b
--- /dev/null
@@ -0,0 +1,174 @@
+====
+ifup
+====
+
+-------------------------------------
+network interface management commands 
+-------------------------------------
+
+:Author: Roopa Prabhu <roopa@cumulusnetworks.com>
+:Date:   2014-02-05
+:Copyright: Copyright 2014 Cumulus Networks, Inc.  All rights reserved.
+:Version: 0.1
+:Manual section: 8
+
+NAME
+====
+    **ifup** - bring a network interface up
+
+    **ifdown** - take a network interface down
+
+SYNOPSIS
+========
+
+    ifup [-h] [-a] [-v] [-d] [--allow CLASS] [--with-depends]
+       **[-X EXCLUDEPATS] [-f] [-n] [--print-dependency {list,dot}]**
+       **[IFACE [IFACE ...]]**
+
+    ifdown [-h] [-a] [-v] [-d] [--allow CLASS] [--with-depends]
+           **[-X EXCLUDEPATS] [-f] [-n] [--print-dependency {list,dot}]**
+           **[IFACE [IFACE ...]]**
+
+DESCRIPTION
+===========
+    **ifup** and **ifdown** commands can be used to configure (or, respectively,
+    deconfigure) network interfaces based on interface definitions in the
+    file **/etc/network/interfaces/** file.
+
+    **ifquery(8)** maybe used in conjunction with **ifup** and **ifdown**
+    commands to query and validate applied/running configuration.
+
+    **ifup** always works on the current **interfaces(5)** file under
+    **/etc/network/interfaces**. **ifdown** works on the last applied interface
+    configuration.
+
+    **ifup** on an already ifup'ed interface will re-apply the configuration,
+    skipping already applied configuration whereever possible. In many cases
+    where config commands are idempotent, you will see that ifup/ifdown will
+    reapply the config even if the interface already has that config.
+
+    **ifup** and **ifdown** understands interface dependency order.
+
+    For logical interfaces like vlans, bridges, bonds, **ifup** creates the
+    interface and **ifdown** deletes the interface. Use **--admin-state**
+    option if you only want to administratively bring the interface up/down.
+
+    When **ifup** and **ifdown** are used with interfaces on command line,
+    they must be have a **iface** section in the **interfaces(5)** file.
+
+OPTIONS
+=======
+    positional arguments:
+
+    **IFACE**  interface list separated by spaces. **IFACE** list and **'-a'**
+    argument are mutually exclusive.
+
+    optional arguments:
+
+    -h, --help            show this help message and exit
+
+    -a, --all             process all interfaces marked "auto"
+
+    -v, --verbose         verbose
+
+    -d, --debug           output debug info
+    --allow CLASS         ignore non-"allow-CLASS" interfaces
+
+    -w, --with-depends        run with all dependent interfaces. This option
+                          is redundant when -a is specified. When '-a' is
+                          specified, interfaces are always executed in
+                          dependency order.
+                        
+    -X EXCLUDEPATS, --exclude EXCLUDEPATS
+                          Exclude interfaces from the list of interfaces to
+                          operate on. Can be specified multiple times
+
+    -i INTERFACESFILE, --interfaces INTERFACESFILE
+                          Use interfaces file instead of default
+                          /etc/network/interfaces
+
+    -t {native,json}, --interfaces-format {native,json}
+                          interfaces file format
+
+    -f, --force           force run all operations
+
+    -n, --no-act          print out what would happen, but don't do it
+
+    -p, --print-dependency {list,dot}
+                          print iface dependency in list or dot format
+
+    -m, --admin-state, --no-scripts
+                          dont run any addon modules/scripts. Only bring
+                          the interface administratively up/down
+
+    -u, --use-current-config
+                          By default ifdown looks at the saved state for
+                          interfaces to bring down. This option allows ifdown
+                          to look at the current interfaces file. Useful when
+                          your state file is corrupted or you want down to use
+                          the latest from the interfaces file
+
+EXAMPLES
+========
+    # bringing up all interfaces
+
+        **ifup -a**
+
+    # bringing up interface list
+
+        **ifup swp1 swp2**
+
+    # bringing up interface with its dependents
+
+        **ifup br0 --with-depends**
+
+    # bringing down all interfaces
+
+        **ifdown -a**
+
+    # bringing down a single interface
+
+        **ifdown swp1**
+
+    # excluding interfaces using -X option
+
+        **ifdown -X eth0 -a**
+
+        **ifup -X eth0 -a**
+
+        **ifdown -X eth0 -X lo -a**
+
+    # using verbose -v option to see what is going on
+
+        **ifup -v -a**
+
+    # using debug -d option to see more of what is going on
+
+        **ifup -d -a**
+
+    # ignore errors
+
+        **ifup -a -f**
+
+        **ifdown -a -f**
+
+    # run ifdown and ifup on all interfaces using service command/init script
+
+        **service networking restart**
+
+    # run ifup on all interfaces using service command/init script
+
+        **service networking start**
+
+    # ifdown on all interfaces using service command/init script
+
+        **service networking stop**
+
+    # To run ifup/ifdown on only interfaces that changed see **ifreload(8)**
+
+SEE ALSO
+========
+    ifquery(8),
+    ifreload(8),
+    interfaces(5),
+    ifupdown-addons-interfaces(5)
diff --git a/man.rst/ifupdown-addons-interfaces.5.rst b/man.rst/ifupdown-addons-interfaces.5.rst
new file mode 100644 (file)
index 0000000..94e2f7c
--- /dev/null
@@ -0,0 +1,1373 @@
+==========================
+ifupdown-addons-interfaces
+==========================
+---------------------------------------------------------
+ifupdown2 addon modules interface configuration
+---------------------------------------------------------
+:Author: roopa@cumulusnetworks.com
+:Date:   2013-09-25
+:Copyright: Copyright 2013 Cumulus Networks, Inc.  All rights reserved.
+:Version: 0.1
+:Manual section: 5
+
+
+DESCRIPTION
+===========
+    ifupdown2 addon modules add incremental functionality to
+    core ifupdown2 tool.
+           
+    All installed addon modules are executed on every interface
+    listed in the interfaces file. Addon modules are installed under
+    /usr/share/ifupdownaddons. To see the list of active addon
+    modules, see ifaddon(8).
+
+    Addon modules add new attributes to the interfaces(5) file.
+    Below is a list of attribute options provided by each module.
+    These can be listed under each iface section in the interfaces(5)
+    file.  
+
+
+EXAMPLES
+========
+    Listed below are addon modules and their supported attributes.
+    The attributes if applicable go under the iface section in the
+    interfaces(5) file.
+
+    **ethtool**: ethtool configuration module for interfaces
+
+
+      **link-duplex**
+
+        **help**: set link duplex
+
+
+        **required**: False
+
+        **default**: half
+
+        **validvals**: half,full
+
+        **example**:
+            link-duplex full
+
+
+      **link-autoneg**
+
+        **help**: set autonegotiation
+
+
+        **required**: False
+
+        **default**: off
+
+        **validvals**: on,off
+
+        **example**:
+            link-autoneg on
+
+
+      **link-speed**
+
+        **help**: set link speed
+
+
+        **required**: False
+
+        **example**:
+            link-speed 1000
+
+
+
+    **bridge**: Bridge configuration module. Supports both vlan aware 
+    and non vlan aware bridges. For the vlan aware bridge, the port sp
+    ecific attributes must be specified under the port. And for vlan u
+    naware bridge port specific attributes must be specified under the
+    bridge.
+
+
+      **bridge-vlan-aware**
+
+        **help**: vlan aware bridge. Setting this attribute to yes ena
+        bles vlan filtering on the bridge
+
+
+        **required**: False
+
+        **example**:
+            bridge-vlan-aware yes/no
+
+
+      **bridge-pathcosts**
+
+        **help**: bridge set port path costs
+
+
+        **required**: False
+
+        **default**: 100
+
+        **example**:
+            bridge-pathcosts swp1=100 swp2=100
+
+
+      **bridge-portprios**
+
+        **help**: bridge port prios
+
+
+        **required**: False
+
+        **default**: 32
+
+        **example**:
+            bridge-portprios swp1=32 swp2=32
+
+
+      **bridge-fd**
+
+        **help**: bridge forward delay
+
+
+        **required**: False
+
+        **default**: 15
+
+        **example**:
+            bridge-fd 15
+
+
+      **bridge-ageing**
+
+        **help**: bridge ageing
+
+
+        **required**: False
+
+        **default**: 300
+
+        **example**:
+            bridge-ageing 300
+
+
+      **bridge-hello**
+
+        **help**: bridge set hello time
+
+
+        **required**: False
+
+        **default**: 2
+
+        **example**:
+            bridge-hello 2
+
+
+      **bridge-gcint**
+
+        **help**: bridge garbage collection interval in secs
+
+
+        **required**: False
+
+        **default**: 4
+
+        **example**:
+            bridge-gcint 4
+
+
+      **bridge-mcquerier**
+
+        **help**: set multicast querier
+
+
+        **required**: False
+
+        **default**: 0
+
+        **example**:
+            bridge-mcquerier 0
+
+
+      **bridge-mclmc**
+
+        **help**: set multicast last member count
+
+
+        **required**: False
+
+        **default**: 2
+
+        **example**:
+            bridge-mclmc 2
+
+
+      **bridge-mcsqc**
+
+        **help**: set multicast startup query count
+
+
+        **required**: False
+
+        **default**: 2
+
+        **example**:
+            bridge-mcsqc 2
+
+
+      **bridge-mcrouter**
+
+        **help**: set multicast router
+
+
+        **required**: False
+
+        **default**: 1
+
+        **example**:
+            bridge-mcrouter 1
+
+
+      **bridge-stp**
+
+        **help**: bridge-stp yes/no
+
+
+        **required**: False
+
+        **default**: no
+
+        **validvals**: yes,on,off,no
+
+        **example**:
+            bridge-stp no
+
+
+      **bridge-pvid**
+
+        **help**: bridge port pvid. Must be specified under the bridge
+        port
+
+
+        **required**: False
+
+        **example**:
+            bridge-pvid 1
+
+
+      **bridge-mcsqi**
+
+        **help**: set multicast startup query interval (in secs)
+
+
+        **required**: False
+
+        **default**: 31
+
+        **example**:
+            bridge-mcsqi 31
+
+
+      **bridge-mcmi**
+
+        **help**: set multicast membership interval (in secs)
+
+
+        **required**: False
+
+        **default**: 260
+
+        **example**:
+            bridge-mcmi 260
+
+
+      **bridge-mclmi**
+
+        **help**: set multicast last member interval (in secs)
+
+
+        **required**: False
+
+        **default**: 1
+
+        **example**:
+            bridge-mclmi 1
+
+
+      **bridge-vids**
+
+        **help**: bridge port vids. Can be specified under the bridge 
+        or under the port. If specified under the bridge the ports inh
+        erit it unless overridden by a bridge-vids attribuet under the
+        port
+
+
+        **required**: False
+
+        **example**:
+            bridge-vids 4000
+
+            bridge-vids 2000 2200-3000
+
+
+      **bridge-ports**
+
+        **help**: bridge ports
+
+
+        **required**: True
+
+        **example**:
+            bridge-ports swp1.100 swp2.100 swp3.100
+
+            bridge-ports glob swp1-3.100
+
+            bridge-ports regex (swp[1|2|3].100)
+
+
+      **bridge-mcqifaddr**
+
+        **help**: set multicast query to use ifaddr
+
+
+        **required**: False
+
+        **default**: 0
+
+        **example**:
+            bridge-mcqifaddr 0
+
+
+      **bridge-waitport**
+
+        **help**: wait for a max of time secs for the specified ports 
+        to become available,if no ports are specified then those speci
+        fied on bridge-ports will be used here. Specifying no ports he
+        re should not be used if we are using regex or "all" on bridge
+        _ports,as it wouldnt work.
+
+
+        **required**: False
+
+        **default**: 0
+
+        **example**:
+            bridge-waitport 4 swp1 swp2
+
+
+      **bridge-mcqri**
+
+        **help**: set multicast query response interval (in secs)
+
+
+        **required**: False
+
+        **default**: 10
+
+        **example**:
+            bridge-mcqri 10
+
+
+      **bridge-hashel**
+
+        **help**: set hash elasticity
+
+
+        **required**: False
+
+        **default**: 4096
+
+        **example**:
+            bridge-hashel 4096
+
+
+      **bridge-mcqpi**
+
+        **help**: set multicast querier interval (in secs)
+
+
+        **required**: False
+
+        **default**: 255
+
+        **example**:
+            bridge-mcqpi 255
+
+
+      **bridge-hashmax**
+
+        **help**: set hash max
+
+
+        **required**: False
+
+        **default**: 4096
+
+        **example**:
+            bridge-hashmax 4096
+
+
+      **bridge-bridgeprio**
+
+        **help**: bridge priority
+
+
+        **required**: False
+
+        **default**: 32768
+
+        **example**:
+            bridge-bridgeprio 32768
+
+
+      **bridge-maxage**
+
+        **help**: bridge set maxage
+
+
+        **required**: False
+
+        **default**: 20
+
+        **example**:
+            bridge-maxage 20
+
+
+      **bridge-mcsnoop**
+
+        **help**: set multicast snooping
+
+
+        **required**: False
+
+        **default**: 1
+
+        **example**:
+            bridge-mcsnoop 1
+
+
+      **bridge-access**
+
+        **help**: bridge port access vlan. Must be specified under the
+        bridge port
+
+
+        **required**: False
+
+        **example**:
+            bridge-access 300
+
+
+      **bridge-maxwait**
+
+        **help**: forces to time seconds the maximum time that the Deb
+        ian bridge setup  scripts will wait for the bridge ports to ge
+        t to the forwarding status, doesn't allow factional part. If i
+        t is equal to 0 then no waiting is done
+
+
+        **required**: False
+
+        **default**: 0
+
+        **example**:
+            bridge-maxwait 3
+
+
+      **bridge-portmcrouter**
+
+        **help**: set port multicast routers
+
+
+        **required**: False
+
+        **default**: 1
+
+        **example**:
+            under the bridge: bridge-portmcrouter swp1=1 swp2=1
+
+            under the port: bridge-portmcrouter 1
+
+
+      **bridge-portmcfl**
+
+        **help**: port multicast fast leave.
+
+
+        **required**: False
+
+        **default**: 0
+
+        **example**:
+            under the bridge: bridge-portmcfl swp1=0 swp2=0
+
+            under the port: bridge-portmcfl 0
+
+
+      **bridge-mcqi**
+
+        **help**: set multicast query interval (in secs)
+
+
+        **required**: False
+
+        **default**: 125
+
+        **example**:
+            bridge-mcqi 125
+
+
+
+    **usercmds**: user commands for interfaces
+
+
+      **down**
+
+        **help**: run command at interface down
+
+
+        **required**: False
+
+      **post-up**
+
+        **help**: run command after interface bring up
+
+
+        **required**: False
+
+      **up**
+
+        **help**: run command at interface bring up
+
+
+        **required**: False
+
+      **pre-down**
+
+        **help**: run command before bringing the interface down
+
+
+        **required**: False
+
+      **pre-up**
+
+        **help**: run command before bringing the interface up
+
+
+        **required**: False
+
+      **post-down**
+
+        **help**: run command after bringing interface down
+
+
+        **required**: False
+
+
+    **mstpctl**: mstp configuration module for bridges
+
+
+      **mstpctl-portadminedge**
+
+        **help**: enable/disable initial edge state of the port
+
+
+        **required**: False
+
+        **default**: no
+
+        **validvals**: yes,no
+
+        **example**:
+            mstpctl-portadminedge swp1=no swp2=no
+
+
+      **mstpctl-portbpdufilter**
+
+        **help**: enable/disable bpdu filter on a port. syntax varies 
+        when defined under a bridge vs under a port
+
+
+        **required**: False
+
+        **default**: no
+
+        **validvals**: yes,no
+
+        **example**:
+            under a bridge: mstpctl-portbpdufilter swp1=no swp2=no
+
+            under a port: mstpctl-portbpdufilter yes
+
+
+      **mstpctl-fdelay**
+
+        **help**: set forwarding delay
+
+
+        **required**: False
+
+        **default**: 15
+
+        **example**:
+            mstpctl-fdelay 15
+
+
+      **mstpctl-portnetwork**
+
+        **help**: enable/disable bridge assurance capability for a por
+        t
+
+
+        **required**: False
+
+        **default**: no
+
+        **validvals**: yes,no
+
+        **example**:
+            mstpctl-portnetwork swp1=no swp2=no
+
+
+      **mstpctl-txholdcount**
+
+        **help**: bridge transmit holdcount
+
+
+        **required**: False
+
+        **default**: 6
+
+        **example**:
+            mstpctl-txholdcount 6
+
+
+      **mstpctl-forcevers**
+
+        **help**: bridge force stp version
+
+
+        **required**: False
+
+        **default**: rstp
+
+        **example**:
+            mstpctl-forcevers rstp
+
+
+      **mstpctl-portautoedge**
+
+        **help**: enable/disable auto transition to/from edge state of
+        the port
+
+
+        **required**: False
+
+        **default**: yes
+
+        **validvals**: yes,no
+
+        **example**:
+            mstpctl-portautoedge swp1=yes swp2=yes
+
+
+      **mstpctl-maxhops**
+
+        **help**: bridge max hops
+
+
+        **required**: False
+
+        **default**: 15
+
+        **example**:
+            mstpctl-maxhops 15
+
+
+      **mstpctl-treeprio**
+
+        **help**: tree priority
+
+
+        **required**: False
+
+        **default**: 32768
+
+        validrange: 0-65535
+
+        **example**:
+            mstpctl-treeprio 32768
+
+
+      **mstpctl-treeportprio**
+
+        **help**: port priority for MSTI instance
+
+
+        **required**: False
+
+        **default**: 128
+
+        validrange: 0-240
+
+        **example**:
+            mstpctl-treeportprio swp1=128 swp2=128
+
+
+      **mstpctl-portpathcost**
+
+        **help**: bridge port path cost
+
+
+        **required**: False
+
+        **default**: 0
+
+        **example**:
+            mstpctl-portpathcost swp1=0 swp2=1
+
+
+      **mstpctl-portrestrtcn**
+
+        **help**: enable/disable port ability to propagate received to
+        pology change notification of the port
+
+
+        **required**: False
+
+        **default**: no
+
+        **validvals**: yes,no
+
+        **example**:
+            mstpctl-portrestrtcn swp1=no swp2=no
+
+
+      **mstpctl-maxage**
+
+        **help**: max message age
+
+
+        **required**: False
+
+        **default**: 20
+
+        **example**:
+            mstpctl-maxage 20
+
+
+      **mstpctl-hello**
+
+        **help**: set hello time
+
+
+        **required**: False
+
+        **default**: 2
+
+        **example**:
+            mstpctl-hello 2
+
+
+      **mstpctl-portrestrrole**
+
+        **help**: enable/disable port ability to take root role of the
+        port
+
+
+        **required**: False
+
+        **default**: no
+
+        **validvals**: yes,no
+
+        **example**:
+            mstpctl-portrestrrole swp1=no swp2=no
+
+
+      **mstpctl-bpduguard**
+
+        **help**: enable/disable bpduguard
+
+
+        **required**: False
+
+        **default**: no
+
+        **validvals**: yes,no
+
+        **example**:
+            mstpctl-bpduguard swp1=no swp2=no
+
+
+      **mstpctl-ageing**
+
+        **help**: ageing time
+
+
+        **required**: False
+
+        **default**: 300
+
+        **example**:
+            mstpctl-ageing 300
+
+
+      **mstpctl-treeportcost**
+
+        **help**: port tree cost
+
+
+        **required**: False
+
+      **mstpctl-portp2p**
+
+        **help**: bridge port p2p detection mode
+
+
+        **required**: False
+
+        **default**: auto
+
+        **validvals**: yes,no,auto
+
+        **example**:
+            mstpctl-portp2p swp1=no swp2=no
+
+
+
+    **clagd**: This module generates the clagd defaults file.
+
+
+      **clagd-priority**
+
+        **help**: The priority of this clagd switch
+
+
+        **required**: False
+
+        **example**:
+            clagd-priority 30000
+
+
+      **clagd-backup-ip**
+
+        **help**: Backup IP address of the clagd peer
+
+
+        **required**: False
+
+        **example**:
+            clagd-backup-ip 192.1.1.1
+
+
+      **clagd-enable**
+
+        **help**: enable clagd
+
+
+        **required**: False
+
+        **validvals**: yes,no
+
+        **example**:
+            clagd-enable yes
+
+
+      **clag-id**
+
+        **help**: multi-chassis lag id
+
+
+        **required**: False
+
+        **default**: 0
+
+        validrange: 0-65535
+
+        **example**:
+            clag-id 1
+
+
+      **clagd-peer-ip**
+
+        **help**: The IP address of the clagd peer
+
+
+        **required**: True
+
+        **example**:
+            clagd-peer 10.10.10.2
+
+
+      **clagd-sys-mac**
+
+        **help**: The system ID of the CLAG pair
+
+
+        **required**: True
+
+        **example**:
+            clagd-sys-mac 44:38:39:ff:00:00
+
+
+      **clagd-args**
+
+        **help**: Additional command line arguments for clagd
+
+
+        **required**: False
+
+        **example**:
+            clagd-args --log /var/log/clagd.log
+
+            clagd-args --verbose --lacpPoll 10
+
+            clagd-args --debug 0x4
+
+
+
+    **vlan**: vlan module configures vlan interfaces.This module under
+    stands vlan interfaces with dot notations. eg swp1.100. Vlan inter
+    faces with any other names need to have raw device and vlan id att
+    ributes
+
+
+      **vlan-id**
+
+        **help**: vlan id
+
+
+        **required**: False
+
+      **vlan-raw-device**
+
+        **help**: vlan raw device
+
+
+        **required**: False
+
+
+    **bridgevlan**: bridgevlan module configures vlan attributes on a 
+    vlan aware bridge. This module only understands vlan interface nam
+    e with dot notations. eg br0.100. where br0 is the vlan aware brid
+    ge this config is for
+
+
+      **bridge-igmp-querier-src**
+
+        **help**: bridge igmp querier src. Must be specified under the
+        vlan interface
+
+
+        **required**: False
+
+        **example**:
+            bridge-igmp-querier-src 172.16.101.1
+
+
+
+    **ifenslave**: bond configuration module
+
+
+      **bond-use-carrier**
+
+        **help**: bond use carrier
+
+
+        **required**: False
+
+        **default**: 1
+
+        **validvals**: 0,1
+
+        **example**:
+            bond-use-carrier 1
+
+
+      **bond-lacp-bypass-period**
+
+        **help**: grace period (seconds) for lacp bypass
+
+
+        **required**: False
+
+        **default**: 0
+
+        validrange: 0-900
+
+        **example**:
+            bond-lacp-bypass-period 100
+
+
+      **bond-miimon**
+
+        **help**: bond miimon
+
+
+        **required**: False
+
+        **default**: 0
+
+        validrange: 0-255
+
+        **example**:
+            bond-miimon 0
+
+
+      **bond-lacp-rate**
+
+        **help**: bond lacp rate
+
+
+        **required**: False
+
+        **default**: 0
+
+        **validvals**: 0,1
+
+        **example**:
+            bond-lacp-rate 0
+
+
+      **bond-lacp-bypass-priority**
+
+        **help**: slave priority for lacp bypass
+
+
+        **required**: False
+
+        **example**:
+            bond-lacp-bypass-priority swp1=1 swp2=1 swp3=2
+
+
+      **bond-min-links**
+
+        **help**: bond min links
+
+
+        **required**: False
+
+        **default**: 0
+
+        **example**:
+            bond-min-links 0
+
+
+      **bond-slaves**
+
+        **help**: bond slaves
+
+
+        **required**: True
+
+        **example**:
+            bond-slaves swp1 swp2
+
+            bond-slaves glob swp1-2
+
+            bond-slaves regex (swp[1|2)
+
+
+      **bond-lacp-bypass-allow**
+
+        **help**: allow lacp bypass
+
+
+        **required**: False
+
+        **default**: 0
+
+        **validvals**: 0,1
+
+        **example**:
+            bond-lacp-bypass-allow 0
+
+
+      **bond-mode**
+
+        **help**: bond mode
+
+
+        **required**: False
+
+        **default**: balance-rr
+
+        **validvals**: balance-rr,active-backup,balance-xor,broadcast,802.3ad,balance-tlb,balance-alb
+
+        **example**:
+            bond-mode 802.3ad
+
+
+      **bond-num-unsol-na**
+
+        **help**: bond slave devices
+
+
+        **required**: False
+
+        **default**: 1
+
+        validrange: 0-255
+
+        **example**:
+            bond-num-unsol-na 1
+
+
+      **bond-ad-sys-priority**
+
+        **help**: 802.3ad system priority
+
+
+        **required**: False
+
+        **default**: 65535
+
+        **example**:
+            bond-ad-sys-priority 65535
+
+
+      **bond-xmit-hash-policy**
+
+        **help**: bond slave devices
+
+
+        **required**: False
+
+        **default**: layer2
+
+        **validvals**: layer2,layer3+4,layer2+3
+
+        **example**:
+            bond-xmit-hash-policy layer2
+
+
+      **bond-num-grat-arp**
+
+        **help**: bond use carrier
+
+
+        **required**: False
+
+        **default**: 1
+
+        validrange: 0-255
+
+        **example**:
+            bond-num-grat-arp 1
+
+
+      **bond-ad-sys-mac-addr**
+
+        **help**: 802.3ad system mac address
+
+
+        **required**: False
+
+        **default**: 00:00:00:00:00:00
+
+        **example**:
+            bond-ad-sys-mac-addr 00:00:00:00:00:00
+
+
+
+    **address**: address configuration module for interfaces
+
+
+      **broadcast**
+
+        **help**: broadcast address
+
+
+        **required**: False
+
+        **example**:
+            broadcast 10.0.1.255
+
+
+      **hwaddress**
+
+        **help**: hw address
+
+
+        **required**: False
+
+        **example**:
+            hwaddress 44:38:39:00:27:b8
+
+
+      **alias**
+
+        **help**: description/alias
+
+
+        **required**: False
+
+        **example**:
+            alias testnetwork
+
+
+      **address**
+
+        **help**: ipv4 or ipv6 addresses
+
+
+        **required**: False
+
+        **example**:
+            address 10.0.12.3/24
+
+            address 2000:1000:1000:1000:3::5/128
+
+
+      **scope**
+
+        **help**: scope
+
+
+        **required**: False
+
+        **example**:
+            scope host
+
+
+      **address-purge**
+
+        **help**: purge existing addresses. By default any existing ip
+        addresses on an interface are purged to match persistant addre
+        sses in the interfaces file. Set this attribute to 'no'if you 
+        want to preserve existing addresses
+
+
+        **required**: False
+
+        **default**: yes
+
+        **example**:
+            address-purge yes/no
+
+
+      **preferred-lifetime**
+
+        **help**: preferred lifetime
+
+
+        **required**: False
+
+        **example**:
+            preferred-lifetime forever
+
+            preferred-lifetime 10
+
+
+      **gateway**
+
+        **help**: default gateway
+
+
+        **required**: False
+
+        **example**:
+            gateway 255.255.255.0
+
+
+      **mtu**
+
+        **help**: interface mtu
+
+
+        **required**: False
+
+        **default**: 1500
+
+        **example**:
+            mtu 1600
+
+
+
+    **addressvirtual**: address module configures virtual addresses fo
+    r interfaces. It creates a macvlan interface for every mac ip addr
+    ess-virtual line
+
+
+      **address-virtual**
+
+        **help**: bridge router virtual mac and ip
+
+
+        **required**: False
+
+        **example**:
+            address-virtual 00:11:22:33:44:01 11.0.1.254/24 11.0.1.254/24
+
+
+
+    **vxlan**: vxlan module configures vxlan interfaces.
+
+
+      **vxlan-learning**
+
+        **help**: vxlan learning on/off
+
+
+        **required**: False
+
+        **default**: on
+
+        **example**:
+            vxlan-learning off
+
+
+      **vxlan-id**
+
+        **help**: vxlan id
+
+
+        **required**: True
+
+        **example**:
+            vxlan-id 100
+
+
+      **vxlan-remoteip**
+
+        **help**: vxlan remote ip
+
+
+        **required**: False
+
+        **example**:
+            vxlan-remoteip 172.16.22.127
+
+
+      **vxlan-svcnodeip**
+
+        **help**: vxlan id
+
+
+        **required**: False
+
+        **example**:
+            vxlan-svcnodeip 172.16.22.125
+
+
+      **vxlan-local-tunnelip**
+
+        **help**: vxlan local tunnel ip
+
+
+        **required**: False
+
+        **example**:
+            vxlan-local-tunnelip 172.16.20.103
+
+
+
+SEE ALSO
+========
+    interfaces(5),
+    ifup(8),
+    ip(8),
+    mstpctl(8),
+    brctl(8),
+    ethtool(8),
+    clagctl(8)
diff --git a/man.rst/interfaces.5.rst b/man.rst/interfaces.5.rst
new file mode 100644 (file)
index 0000000..e77e1c9
--- /dev/null
@@ -0,0 +1,155 @@
+==========
+interfaces
+==========
+
+--------------------------------------------
+network interface configuration for ifupdown
+--------------------------------------------
+
+:Author: Roopa Prabhu <roopa@cumulusnetworks.com>
+:Date:   2014-02-05
+:Copyright: Copyright 2014 Cumulus Networks, Inc.  All rights reserved.
+:Version: 0.1
+:Manual section: 5 
+
+DESCRIPTION
+===========
+    **/etc/network/interfaces** contains network interface configuration
+    information for the **ifup(8)**, **ifdown(8)** and **ifquery(8)** commands.
+
+    This is where you configure how your system is connected to the network.
+
+    Lines starting with # are ignored. Note that end-of-line comments are
+    NOT supported, comments must be on a line of their own.
+
+    A line may be extended across multiple lines by making the last character
+    a backslash.
+
+    The file consists of zero or more "iface", "auto",  "allow-"
+    and "source" stanzas. Here is an example::
+
+        auto lo eth0
+        allow-hotplug eth1
+
+        iface lo inet loopback
+
+        source /etc/network/interfaces.d/bridges
+
+        iface eth0 inet static
+            address 192.168.1.1/24
+            up flush-mail
+
+        iface eth1 inet dhcp
+
+    Lines beginning with the word "auto" are used to identify the physical
+    interfaces to be brought up when ifup is run with the -a option.
+    (This option is used by the system boot scripts.) Physical interface names
+    should follow the word "auto" on the same line.  There can be  multiple
+    "auto"  stanzas.
+
+    Lines beginning with "allow-" are  used  to  identify  interfaces  that
+    should  be  brought  up automatically by various subsytems. This may be
+    done using a command such as "ifup --allow=hotplug  eth0  eth1",  which
+    will  only  bring up eth0 or eth1 if it is listed in an "allow-hotplug"
+    line. Note that "allow-auto" and "auto" are synonyms.
+
+    Lines beginning with "source" are used to include  stanzas  from  other
+    files, so configuration can be split into many files. The word "source"
+    is followed by the path of file to be sourced. Shell wildcards  can  be
+    used. Currently only supports absolute
+    path names.
+
+    iface is normally given a interface name as its first non-option
+    argument. 
+
+    The interface name is followed by the name of the address family that the
+    interface uses. This will be "inet" for TCP/IP networking and inet6 for
+    ipv6. Following that is the name of the method used to configure the
+    interface.
+
+    ifupdown supports iface stanzas without a family or a method. This enables
+    using the same stanza for inet and inet6 family addresses. And the method
+    defaults to "static"
+
+    Additional interface options/attributes can be given on subsequent lines
+    in the iface stanza. These options come from addon modules. see
+    **ifupdown-addons-interfaces(5)** for these options.
+
+    example bridge interface with additional attributes listed in the
+    **ifupdown-addons-interfaces(5)** man page::
+
+        auto br0
+        iface br0
+            address 12.0.0.4/24
+            address 2000:1000:1000:1000:3::5/128
+            bridge-ports swp1 swp2 swp3
+            bridge-stp on
+
+    ifupdown supports python-mako style templates in the interfaces file.
+    See examples section for details.
+
+    See **/usr/share/doc/python-ifupdown2/examples/** for **interfaces(5)**
+    file examples and interfaces file generation scripts.
+
+METHODS
+=======
+    Both **inet** and **inet6** address family interfaces can use the following
+    methods (However they are not required):
+
+    The loopback Method
+           This method may be used to define the loopback interface.
+
+    The static Method
+           This method may be used to define ethernet interfaces with
+           statically allocated addresses.
+
+    The dhcp Method
+           This method may be used to obtain an address via DHCP.
+
+BUILTIN INTERFACES
+==================
+    **iface** sections for some interfaces like physical interfaces or vlan
+    interfaces in dot notation (like eth1.100) are understood by ifupdown.
+    These interfaces do not need an entry in the interfaces file if
+    they are dependents of other interfaces and dont need any specific
+    configurations like addresses etc.
+
+EXAMPLES
+========
+    Sample /etc/network/interfaces file::
+
+        auto lo
+        iface lo
+            address 192.168.2.0/24
+            address 2001:dee:eeee:1::4/128
+
+        auto eth0
+        iface eth0 inet dhcp
+
+        auto eth1
+        iface eth1 inet manual
+            address 192.168.2.0/24
+            address 2001:dee:eeee:1::4/128
+
+        # source files from a directory /etc/network/interfaces.d
+        source /etc/network/interfaces.d/*
+
+        # Using mako style templates
+        % for v in [11,12]:
+            auto vlan${v}
+            iface vlan${v} inet static
+                address 10.20.${v}.3/24
+        % endfor
+
+    For additional syntax and examples see **ifupdown-addons-interfaces(5)**
+
+FILES
+=====
+    /etc/network/interfaces
+
+SEE ALSO
+========
+    ifupdown-addons-interfaces(5),
+    ifup(8),
+    ifquery(8),
+    ifreload(8)
diff --git a/man/ifquery.8 b/man/ifquery.8
new file mode 100644 (file)
index 0000000..65e89e2
--- /dev/null
@@ -0,0 +1,230 @@
+.\" Man page generated from reStructeredText.
+.
+.TH IFQUERY 8 "2014-02-05" "0.1" ""
+.SH NAME
+ifquery \- query network interface configuration
+.
+.nr rst2man-indent-level 0
+.
+.de1 rstReportMargin
+\\$1 \\n[an-margin]
+level \\n[rst2man-indent-level]
+level margin: \\n[rst2man-indent\\n[rst2man-indent-level]]
+-
+\\n[rst2man-indent0]
+\\n[rst2man-indent1]
+\\n[rst2man-indent2]
+..
+.de1 INDENT
+.\" .rstReportMargin pre:
+. RS \\$1
+. nr rst2man-indent\\n[rst2man-indent-level] \\n[an-margin]
+. nr rst2man-indent-level +1
+.\" .rstReportMargin post:
+..
+.de UNINDENT
+. RE
+.\" indent \\n[an-margin]
+.\" old: \\n[rst2man-indent\\n[rst2man-indent-level]]
+.nr rst2man-indent-level -1
+.\" new: \\n[rst2man-indent\\n[rst2man-indent-level]]
+.in \\n[rst2man-indent\\n[rst2man-indent-level]]u
+..
+.SH SYNOPSIS
+.INDENT 0.0
+.INDENT 3.5
+\fBifquery [\-v] [\-\-allow CLASS] [\-\-with\-depends] \-a|IFACE...\fP
+.sp
+\fBifquery [\-v] [\-r|\-\-running] [\-\-allow CLASS] [\-\-with\-depends] \-a|IFACE...\fP
+.sp
+\fBifquery [\-v] [\-c|\-\-check] [\-\-allow CLASS] [\-\-with\-depends] \-a|IFACE...\fP
+.sp
+\fBifquery [\-v] [\-p|\-\-print\-dependency {list,dot}] [\-\-allow CLASS] [\-\-with\-depends] \-a|IFACE...\fP
+.sp
+\fBifquery [\-v] \-s|\-\-syntax\-help\fP
+.UNINDENT
+.UNINDENT
+.SH DESCRIPTION
+.INDENT 0.0
+.INDENT 3.5
+\fBifquery\fP can be used to parse interface configuration file, query
+running state or check running state of the interface with configuration
+in \fB/etc/network/interfaces\fP file.
+.sp
+\fBifquery\fP always works on the current \fBinterfaces(5)\fP file
+\fB/etc/network/interfaces\fP unless an alternate interfaces file is
+provided with the \fB\-i\fP option.
+.UNINDENT
+.UNINDENT
+.SH OPTIONS
+.INDENT 0.0
+.INDENT 3.5
+positional arguments:
+.sp
+\fBIFACE\fP   interface list separated by spaces. \fBIFACE\fP list and \fB\(aq\-a\(aq\fP argument are mutually exclusive.
+.sp
+optional arguments:
+.INDENT 0.0
+.TP
+.B \-h,  \-\-help
+show this help message and exit
+.TP
+.B \-a,  \-\-all
+process all interfaces marked "auto"
+.TP
+.B \-v,  \-\-verbose
+verbose
+.TP
+.B \-d,  \-\-debug
+output debug info
+.TP
+.BI \-\-allow \ CLASS
+ignore non\-"allow\-CLASS" interfaces
+.TP
+.B \-w,  \-\-with\-depends
+run with all dependent interfaces. This option
+is redundant when \-a is specified. When \(aq\-a\(aq is
+specified, interfaces are always executed in
+dependency order.
+.TP
+.BI \-X \ EXCLUDEPATS, \ \-\-exclude \ EXCLUDEPATS
+Exclude interfaces from the list of interfaces to
+operate on. Can be specified multiple times
+.TP
+.BI \-i \ INTERFACESFILE, \ \-\-interfaces \ INTERFACESFILE
+Use interfaces file instead of default
+/etc/network/interfaces
+.UNINDENT
+.INDENT 0.0
+.TP
+.B \-t {native,json}, \-\-interfaces\-format {native,json}
+interfaces file format
+.UNINDENT
+.INDENT 0.0
+.TP
+.B \-r,  \-\-running
+print raw interfaces file entries
+.TP
+.B \-c,  \-\-check
+check interface file contents against running state
+of an interface. Returns exit code 0 on success and
+1 on error
+.TP
+.B \-x,  \-\-raw
+print raw config file entries
+.UNINDENT
+.INDENT 0.0
+.TP
+.B \-o {native,json}, \-\-format {native,json}
+interface display format
+.TP
+.B \-p, \-\-print\-dependency {list,dot}
+print iface dependency in list or dot format
+.UNINDENT
+.INDENT 0.0
+.TP
+.B \-s,  \-\-syntax\-help
+print supported interface config syntax. Scans all
+addon modules and dumps supported syntax from them
+if provided by the module.
+.UNINDENT
+.UNINDENT
+.UNINDENT
+.SH EXAMPLES
+.INDENT 0.0
+.INDENT 3.5
+# dump all or some interfaces config file entries
+# (pretty prints user provided entries)
+.INDENT 0.0
+.INDENT 3.5
+\fBifquery \-a\fP
+.sp
+\fBifquery br0\fP
+.UNINDENT
+.UNINDENT
+.sp
+# Same as above but dump with dependencies
+.INDENT 0.0
+.INDENT 3.5
+\fBifquery br0 \-\-with\-depends\fP
+.UNINDENT
+.UNINDENT
+.sp
+# Check running state with the config in /etc/network/interfaces
+.INDENT 0.0
+.INDENT 3.5
+\fBifquery \-\-check br0\fP
+.sp
+\fBifquery \-\-check \-\-with\-depends br0\fP
+.sp
+\fBifquery \-\-check \-a\fP
+.UNINDENT
+.UNINDENT
+.sp
+# dump running state of all interfaces in /etc/network/interfaces format
+.INDENT 0.0
+.INDENT 3.5
+\fBifquery \-\-running br0\fP
+.sp
+\fBifquery \-\-running \-\-with\-depends br0\fP
+.sp
+\fBifquery \-\-running \-a\fP
+.UNINDENT
+.UNINDENT
+.sp
+# print dependency info in list format
+.INDENT 0.0
+.INDENT 3.5
+\fBifquery \-\-print\-dependency=list \-a\fP
+.sp
+\fBifquery \-\-print\-dependency=list  br2000\fP
+.UNINDENT
+.UNINDENT
+.sp
+# print dependency info in dot format
+.INDENT 0.0
+.INDENT 3.5
+\fBifquery \-\-print\-dependency=dot \-a\fP
+.sp
+\fBifquery \-\-print\-dependency=dot br2000\fP
+.UNINDENT
+.UNINDENT
+.sp
+# Create an image (png) from the dot format
+.INDENT 0.0
+.INDENT 3.5
+\fBifquery \-\-print\-dependency=dot \-a > interfaces.dot\fP
+.sp
+\fBdot \-Tpng interfaces.dot > interfaces.png\fP
+.sp
+(The above command only works on a system with dot installed)
+.UNINDENT
+.UNINDENT
+.UNINDENT
+.UNINDENT
+.SH KNOWN_ISSUES
+.INDENT 0.0
+.INDENT 3.5
+\fBifquery \-\-check\fP is currently experimental
+.sp
+\fBifquery \-\-check\fP cannot validate usercommands given under pre\-up, post\-up etc
+There is currently no support to check/validate ethtool iface attributes
+.UNINDENT
+.UNINDENT
+.SH SEE ALSO
+.INDENT 0.0
+.INDENT 3.5
+ifup(8),
+ifdown(8),
+ifreload(8),
+interfaces(5),
+ifupdown\-addons\-interfaces(5)
+.UNINDENT
+.UNINDENT
+.SH AUTHOR
+Roopa Prabhu <roopa@cumulusnetworks.com>
+.SH COPYRIGHT
+Copyright 2014 Cumulus Networks, Inc.  All rights reserved.
+.\" Generated by docutils manpage writer.
+.\" 
+.
diff --git a/man/ifreload.8 b/man/ifreload.8
new file mode 100644 (file)
index 0000000..a39da36
--- /dev/null
@@ -0,0 +1,116 @@
+.\" Man page generated from reStructeredText.
+.
+.TH IFRELOAD 8 "2014-02-05" "0.1" ""
+.SH NAME
+ifreload \- reload network interface configuration
+.
+.nr rst2man-indent-level 0
+.
+.de1 rstReportMargin
+\\$1 \\n[an-margin]
+level \\n[rst2man-indent-level]
+level margin: \\n[rst2man-indent\\n[rst2man-indent-level]]
+-
+\\n[rst2man-indent0]
+\\n[rst2man-indent1]
+\\n[rst2man-indent2]
+..
+.de1 INDENT
+.\" .rstReportMargin pre:
+. RS \\$1
+. nr rst2man-indent\\n[rst2man-indent-level] \\n[an-margin]
+. nr rst2man-indent-level +1
+.\" .rstReportMargin post:
+..
+.de UNINDENT
+. RE
+.\" indent \\n[an-margin]
+.\" old: \\n[rst2man-indent\\n[rst2man-indent-level]]
+.nr rst2man-indent-level -1
+.\" new: \\n[rst2man-indent\\n[rst2man-indent-level]]
+.in \\n[rst2man-indent\\n[rst2man-indent-level]]u
+..
+.SH SYNOPSIS
+.INDENT 0.0
+.INDENT 3.5
+ifreload [\-h] (\-a|\-c) [\-v] [\-d] [\-f] [\-n]
+.UNINDENT
+.UNINDENT
+.SH DESCRIPTION
+.INDENT 0.0
+.INDENT 3.5
+reloads network \fBinterfaces(5)\fP file \fB/etc/network/interfaces\fP.
+.sp
+Runs \fBifdown\fP on interfaces that changed in the interfaces file and
+subsequently runs \fBifup\fP on all interfaces.
+.sp
+\fBifreload\fP is equivalent to \fBifdown \-a\fP followed by \fBifup \-a\fP
+but it skips \fBifdown\fP for interfaces that did not change in the config
+file.
+.sp
+If you do not wish to execute \fBdown\fP on any interfaces, but only \fBup\fP on
+interfaces that were already \fBup\fP, please see the \fB\-\-currently\-up\fP
+option below.
+.UNINDENT
+.UNINDENT
+.SH OPTIONS
+.INDENT 0.0
+.INDENT 3.5
+.INDENT 0.0
+.TP
+.B \-h,  \-\-help
+show this help message and exit
+.TP
+.B \-a,  \-\-all
+process all interfaces marked "auto"
+.TP
+.B \-v,  \-\-verbose
+verbose
+.TP
+.B \-d,  \-\-debug
+output debug info
+.TP
+.B \-f,  \-\-force
+force run all operations
+.TP
+.B \-c,  \-\-currently\-up
+only reload auto and other interfaces that are
+currently up. This can be used as a non\-disruptive
+alternative to \-a because it will not down any
+interfaces
+.UNINDENT
+.UNINDENT
+.UNINDENT
+.SH EXAMPLES
+.INDENT 0.0
+.INDENT 3.5
+# reload all auto interfaces in \fBinterfaces(5)\fP file
+.sp
+\fBifreload \-a\fP
+.sp
+# reload all interfaces using service command
+.sp
+\fBservice networking reload\fP
+.sp
+# reload all currently up interfaces without bringing any interfaces down
+.sp
+\fBservice networking reload\-currently\-up\fP
+.UNINDENT
+.UNINDENT
+.SH SEE ALSO
+.INDENT 0.0
+.INDENT 3.5
+ifup(8),
+ifdown(8),
+ifquery(8),
+interfaces(5),
+ifupdown\-addons\-interfaces(5)
+.UNINDENT
+.UNINDENT
+.SH AUTHOR
+Roopa Prabhu <roopa@cumulusnetworks.com>
+.SH COPYRIGHT
+Copyright 2014 Cumulus Networks, Inc.  All rights reserved.
+.\" Generated by docutils manpage writer.
+.\" 
+.
diff --git a/man/ifup.8 b/man/ifup.8
new file mode 100644 (file)
index 0000000..ae72d9f
--- /dev/null
@@ -0,0 +1,269 @@
+.\" Man page generated from reStructeredText.
+.
+.TH IFUP 8 "2014-02-05" "0.1" ""
+.SH NAME
+ifup \- network interface management commands
+.
+.nr rst2man-indent-level 0
+.
+.de1 rstReportMargin
+\\$1 \\n[an-margin]
+level \\n[rst2man-indent-level]
+level margin: \\n[rst2man-indent\\n[rst2man-indent-level]]
+-
+\\n[rst2man-indent0]
+\\n[rst2man-indent1]
+\\n[rst2man-indent2]
+..
+.de1 INDENT
+.\" .rstReportMargin pre:
+. RS \\$1
+. nr rst2man-indent\\n[rst2man-indent-level] \\n[an-margin]
+. nr rst2man-indent-level +1
+.\" .rstReportMargin post:
+..
+.de UNINDENT
+. RE
+.\" indent \\n[an-margin]
+.\" old: \\n[rst2man-indent\\n[rst2man-indent-level]]
+.nr rst2man-indent-level -1
+.\" new: \\n[rst2man-indent\\n[rst2man-indent-level]]
+.in \\n[rst2man-indent\\n[rst2man-indent-level]]u
+..
+.SH NAME
+.INDENT 0.0
+.INDENT 3.5
+\fBifup\fP \- bring a network interface up
+.sp
+\fBifdown\fP \- take a network interface down
+.UNINDENT
+.UNINDENT
+.SH SYNOPSIS
+.INDENT 0.0
+.INDENT 3.5
+.INDENT 0.0
+.TP
+.B ifup [\-h] [\-a] [\-v] [\-d] [\-\-allow CLASS] [\-\-with\-depends]
+\fB[\-X EXCLUDEPATS] [\-f] [\-n] [\-\-print\-dependency {list,dot}]\fP
+\fB[IFACE [IFACE ...]]\fP
+.TP
+.B ifdown [\-h] [\-a] [\-v] [\-d] [\-\-allow CLASS] [\-\-with\-depends]
+\fB[\-X EXCLUDEPATS] [\-f] [\-n] [\-\-print\-dependency {list,dot}]\fP
+\fB[IFACE [IFACE ...]]\fP
+.UNINDENT
+.UNINDENT
+.UNINDENT
+.SH DESCRIPTION
+.INDENT 0.0
+.INDENT 3.5
+\fBifup\fP and \fBifdown\fP commands can be used to configure (or, respectively,
+deconfigure) network interfaces based on interface definitions in the
+file \fB/etc/network/interfaces/\fP file.
+.sp
+\fBifquery(8)\fP maybe used in conjunction with \fBifup\fP and \fBifdown\fP
+commands to query and validate applied/running configuration.
+.sp
+\fBifup\fP always works on the current \fBinterfaces(5)\fP file under
+\fB/etc/network/interfaces\fP. \fBifdown\fP works on the last applied interface
+configuration.
+.sp
+\fBifup\fP on an already ifup\(aqed interface will re\-apply the configuration,
+skipping already applied configuration whereever possible. In many cases
+where config commands are idempotent, you will see that ifup/ifdown will
+reapply the config even if the interface already has that config.
+.sp
+\fBifup\fP and \fBifdown\fP understands interface dependency order.
+.sp
+For logical interfaces like vlans, bridges, bonds, \fBifup\fP creates the
+interface and \fBifdown\fP deletes the interface. Use \fB\-\-admin\-state\fP
+option if you only want to administratively bring the interface up/down.
+.sp
+When \fBifup\fP and \fBifdown\fP are used with interfaces on command line,
+they must be have a \fBiface\fP section in the \fBinterfaces(5)\fP file.
+.UNINDENT
+.UNINDENT
+.SH OPTIONS
+.INDENT 0.0
+.INDENT 3.5
+positional arguments:
+.sp
+\fBIFACE\fP  interface list separated by spaces. \fBIFACE\fP list and \fB\(aq\-a\(aq\fP
+argument are mutually exclusive.
+.sp
+optional arguments:
+.INDENT 0.0
+.TP
+.B \-h,  \-\-help
+show this help message and exit
+.TP
+.B \-a,  \-\-all
+process all interfaces marked "auto"
+.TP
+.B \-v,  \-\-verbose
+verbose
+.TP
+.B \-d,  \-\-debug
+output debug info
+.TP
+.BI \-\-allow \ CLASS
+ignore non\-"allow\-CLASS" interfaces
+.TP
+.B \-w,  \-\-with\-depends
+run with all dependent interfaces. This option
+is redundant when \-a is specified. When \(aq\-a\(aq is
+specified, interfaces are always executed in
+dependency order.
+.TP
+.BI \-X \ EXCLUDEPATS, \ \-\-exclude \ EXCLUDEPATS
+Exclude interfaces from the list of interfaces to
+operate on. Can be specified multiple times
+.TP
+.BI \-i \ INTERFACESFILE, \ \-\-interfaces \ INTERFACESFILE
+Use interfaces file instead of default
+/etc/network/interfaces
+.UNINDENT
+.INDENT 0.0
+.TP
+.B \-t {native,json}, \-\-interfaces\-format {native,json}
+interfaces file format
+.UNINDENT
+.INDENT 0.0
+.TP
+.B \-f,  \-\-force
+force run all operations
+.TP
+.B \-n,  \-\-no\-act
+print out what would happen, but don\(aqt do it
+.UNINDENT
+.INDENT 0.0
+.TP
+.B \-p, \-\-print\-dependency {list,dot}
+print iface dependency in list or dot format
+.UNINDENT
+.INDENT 0.0
+.TP
+.B \-m,  \-\-admin\-state,  \-\-no\-scripts
+dont run any addon modules/scripts. Only bring
+the interface administratively up/down
+.TP
+.B \-u,  \-\-use\-current\-config
+By default ifdown looks at the saved state for
+interfaces to bring down. This option allows ifdown
+to look at the current interfaces file. Useful when
+your state file is corrupted or you want down to use
+the latest from the interfaces file
+.UNINDENT
+.UNINDENT
+.UNINDENT
+.SH EXAMPLES
+.INDENT 0.0
+.INDENT 3.5
+# bringing up all interfaces
+.INDENT 0.0
+.INDENT 3.5
+\fBifup \-a\fP
+.UNINDENT
+.UNINDENT
+.sp
+# bringing up interface list
+.INDENT 0.0
+.INDENT 3.5
+\fBifup swp1 swp2\fP
+.UNINDENT
+.UNINDENT
+.sp
+# bringing up interface with its dependents
+.INDENT 0.0
+.INDENT 3.5
+\fBifup br0 \-\-with\-depends\fP
+.UNINDENT
+.UNINDENT
+.sp
+# bringing down all interfaces
+.INDENT 0.0
+.INDENT 3.5
+\fBifdown \-a\fP
+.UNINDENT
+.UNINDENT
+.sp
+# bringing down a single interface
+.INDENT 0.0
+.INDENT 3.5
+\fBifdown swp1\fP
+.UNINDENT
+.UNINDENT
+.sp
+# excluding interfaces using \-X option
+.INDENT 0.0
+.INDENT 3.5
+\fBifdown \-X eth0 \-a\fP
+.sp
+\fBifup \-X eth0 \-a\fP
+.sp
+\fBifdown \-X eth0 \-X lo \-a\fP
+.UNINDENT
+.UNINDENT
+.sp
+# using verbose \-v option to see what is going on
+.INDENT 0.0
+.INDENT 3.5
+\fBifup \-v \-a\fP
+.UNINDENT
+.UNINDENT
+.sp
+# using debug \-d option to see more of what is going on
+.INDENT 0.0
+.INDENT 3.5
+\fBifup \-d \-a\fP
+.UNINDENT
+.UNINDENT
+.sp
+# ignore errors
+.INDENT 0.0
+.INDENT 3.5
+\fBifup \-a \-f\fP
+.sp
+\fBifdown \-a \-f\fP
+.UNINDENT
+.UNINDENT
+.sp
+# run ifdown and ifup on all interfaces using service command/init script
+.INDENT 0.0
+.INDENT 3.5
+\fBservice networking restart\fP
+.UNINDENT
+.UNINDENT
+.sp
+# run ifup on all interfaces using service command/init script
+.INDENT 0.0
+.INDENT 3.5
+\fBservice networking start\fP
+.UNINDENT
+.UNINDENT
+.sp
+# ifdown on all interfaces using service command/init script
+.INDENT 0.0
+.INDENT 3.5
+\fBservice networking stop\fP
+.UNINDENT
+.UNINDENT
+.sp
+# To run ifup/ifdown on only interfaces that changed see \fBifreload(8)\fP
+.UNINDENT
+.UNINDENT
+.SH SEE ALSO
+.INDENT 0.0
+.INDENT 3.5
+ifquery(8),
+ifreload(8),
+interfaces(5),
+ifupdown\-addons\-interfaces(5)
+.UNINDENT
+.UNINDENT
+.SH AUTHOR
+Roopa Prabhu <roopa@cumulusnetworks.com>
+.SH COPYRIGHT
+Copyright 2014 Cumulus Networks, Inc.  All rights reserved.
+.\" Generated by docutils manpage writer.
+.\" 
+.
diff --git a/man/ifupdown-addons-interfaces.5 b/man/ifupdown-addons-interfaces.5
new file mode 100644 (file)
index 0000000..86d71a7
--- /dev/null
@@ -0,0 +1,1343 @@
+.\" Man page generated from reStructeredText.
+.
+.TH IFUPDOWN-ADDONS-INTERFACES 5 "2013-09-25" "0.1" ""
+.SH NAME
+ifupdown-addons-interfaces \- ifupdown2 addon modules interface configuration
+.
+.nr rst2man-indent-level 0
+.
+.de1 rstReportMargin
+\\$1 \\n[an-margin]
+level \\n[rst2man-indent-level]
+level margin: \\n[rst2man-indent\\n[rst2man-indent-level]]
+-
+\\n[rst2man-indent0]
+\\n[rst2man-indent1]
+\\n[rst2man-indent2]
+..
+.de1 INDENT
+.\" .rstReportMargin pre:
+. RS \\$1
+. nr rst2man-indent\\n[rst2man-indent-level] \\n[an-margin]
+. nr rst2man-indent-level +1
+.\" .rstReportMargin post:
+..
+.de UNINDENT
+. RE
+.\" indent \\n[an-margin]
+.\" old: \\n[rst2man-indent\\n[rst2man-indent-level]]
+.nr rst2man-indent-level -1
+.\" new: \\n[rst2man-indent\\n[rst2man-indent-level]]
+.in \\n[rst2man-indent\\n[rst2man-indent-level]]u
+..
+.SH DESCRIPTION
+.INDENT 0.0
+.INDENT 3.5
+ifupdown2 addon modules add incremental functionality to
+core ifupdown2 tool.
+.sp
+All installed addon modules are executed on every interface
+listed in the interfaces file. Addon modules are installed under
+/usr/share/ifupdownaddons. To see the list of active addon
+modules, see ifaddon(8).
+.sp
+Addon modules add new attributes to the interfaces(5) file.
+Below is a list of attribute options provided by each module.
+These can be listed under each iface section in the interfaces(5)
+file.
+.UNINDENT
+.UNINDENT
+.SH EXAMPLES
+.INDENT 0.0
+.INDENT 3.5
+Listed below are addon modules and their supported attributes.
+The attributes if applicable go under the iface section in the
+interfaces(5) file.
+.sp
+\fBethtool\fP: ethtool configuration module for interfaces
+.INDENT 0.0
+.INDENT 3.5
+\fBlink\-duplex\fP
+.INDENT 0.0
+.INDENT 3.5
+\fBhelp\fP: set link duplex
+.sp
+\fBrequired\fP: False
+.sp
+\fBdefault\fP: half
+.sp
+\fBvalidvals\fP: half,full
+.INDENT 0.0
+.TP
+.B \fBexample\fP:
+link\-duplex full
+.UNINDENT
+.UNINDENT
+.UNINDENT
+.sp
+\fBlink\-autoneg\fP
+.INDENT 0.0
+.INDENT 3.5
+\fBhelp\fP: set autonegotiation
+.sp
+\fBrequired\fP: False
+.sp
+\fBdefault\fP: off
+.sp
+\fBvalidvals\fP: on,off
+.INDENT 0.0
+.TP
+.B \fBexample\fP:
+link\-autoneg on
+.UNINDENT
+.UNINDENT
+.UNINDENT
+.sp
+\fBlink\-speed\fP
+.INDENT 0.0
+.INDENT 3.5
+\fBhelp\fP: set link speed
+.sp
+\fBrequired\fP: False
+.INDENT 0.0
+.TP
+.B \fBexample\fP:
+link\-speed 1000
+.UNINDENT
+.UNINDENT
+.UNINDENT
+.UNINDENT
+.UNINDENT
+.sp
+\fBbridge\fP: bridge configuration module
+.INDENT 0.0
+.INDENT 3.5
+\fBbridge\-mcqifaddr\fP
+.INDENT 0.0
+.INDENT 3.5
+\fBhelp\fP: set multicast query to use ifaddr
+.sp
+\fBrequired\fP: False
+.sp
+\fBdefault\fP: 0
+.INDENT 0.0
+.TP
+.B \fBexample\fP:
+bridge\-mcqifaddr 0
+.UNINDENT
+.UNINDENT
+.UNINDENT
+.sp
+\fBbridge\-gcint\fP
+.INDENT 0.0
+.INDENT 3.5
+\fBhelp\fP: bridge garbage collection interval in secs
+.sp
+\fBrequired\fP: False
+.sp
+\fBdefault\fP: 4
+.INDENT 0.0
+.TP
+.B \fBexample\fP:
+bridge\-gcint 4
+.UNINDENT
+.UNINDENT
+.UNINDENT
+.sp
+\fBbridge\-mcsqc\fP
+.INDENT 0.0
+.INDENT 3.5
+\fBhelp\fP: set multicast startup query count
+.sp
+\fBrequired\fP: False
+.sp
+\fBdefault\fP: 2
+.INDENT 0.0
+.TP
+.B \fBexample\fP:
+bridge\-mcsqc 2
+.UNINDENT
+.UNINDENT
+.UNINDENT
+.sp
+\fBbridge\-stp\fP
+.INDENT 0.0
+.INDENT 3.5
+\fBhelp\fP: bridge\-stp yes/no
+.sp
+\fBrequired\fP: False
+.sp
+\fBdefault\fP: no
+.sp
+\fBvalidvals\fP: yes,on,off,no
+.INDENT 0.0
+.TP
+.B \fBexample\fP:
+bridge\-stp no
+.UNINDENT
+.UNINDENT
+.UNINDENT
+.sp
+\fBbridge\-mcsqi\fP
+.INDENT 0.0
+.INDENT 3.5
+\fBhelp\fP: set multicast startup query interval (in secs)
+.sp
+\fBrequired\fP: False
+.sp
+\fBdefault\fP: 31
+.INDENT 0.0
+.TP
+.B \fBexample\fP:
+bridge\-mcsqi 31
+.UNINDENT
+.UNINDENT
+.UNINDENT
+.sp
+\fBbridge\-mcmi\fP
+.INDENT 0.0
+.INDENT 3.5
+\fBhelp\fP: set multicast membership interval (in secs)
+.sp
+\fBrequired\fP: False
+.sp
+\fBdefault\fP: 260
+.INDENT 0.0
+.TP
+.B \fBexample\fP:
+bridge\-mcmi 260
+.UNINDENT
+.UNINDENT
+.UNINDENT
+.sp
+\fBbridge\-ports\fP
+.INDENT 0.0
+.INDENT 3.5
+\fBhelp\fP: bridge ports
+.sp
+\fBrequired\fP: True
+.INDENT 0.0
+.TP
+.B \fBexample\fP:
+bridge\-ports swp1.100 swp2.100 swp3.100
+.sp
+bridge\-ports glob swp1\-3.100
+.sp
+bridge\-ports regex (swp[1|2|3].100)
+.UNINDENT
+.UNINDENT
+.UNINDENT
+.sp
+\fBbridge\-mcsnoop\fP
+.INDENT 0.0
+.INDENT 3.5
+\fBhelp\fP: set multicast snooping
+.sp
+\fBrequired\fP: False
+.sp
+\fBdefault\fP: 1
+.INDENT 0.0
+.TP
+.B \fBexample\fP:
+bridge\-mcsnoop 1
+.UNINDENT
+.UNINDENT
+.UNINDENT
+.sp
+\fBbridge\-maxwait\fP
+.INDENT 0.0
+.INDENT 3.5
+\fBhelp\fP: forces to time seconds the maximum time that the Deb
+ian bridge setup  scripts will wait for the bridge ports to ge
+t to the forwarding status, doesn\(aqt allow factional part. If i
+t is equal to 0 then no waiting is done
+.sp
+\fBrequired\fP: False
+.sp
+\fBdefault\fP: 0
+.INDENT 0.0
+.TP
+.B \fBexample\fP:
+bridge\-maxwait 3
+.UNINDENT
+.UNINDENT
+.UNINDENT
+.sp
+\fBbridge\-pathcosts\fP
+.INDENT 0.0
+.INDENT 3.5
+\fBhelp\fP: bridge set port path costs
+.sp
+\fBrequired\fP: False
+.sp
+\fBdefault\fP: 100
+.INDENT 0.0
+.TP
+.B \fBexample\fP:
+bridge\-pathcosts swp1=100 swp2=100
+.UNINDENT
+.UNINDENT
+.UNINDENT
+.sp
+\fBbridge\-portprios\fP
+.INDENT 0.0
+.INDENT 3.5
+\fBhelp\fP: bridge port prios
+.sp
+\fBrequired\fP: False
+.sp
+\fBdefault\fP: 32
+.INDENT 0.0
+.TP
+.B \fBexample\fP:
+bridge\-portprios swp1=32 swp2=32
+.UNINDENT
+.UNINDENT
+.UNINDENT
+.sp
+\fBbridge\-fd\fP
+.INDENT 0.0
+.INDENT 3.5
+\fBhelp\fP: bridge forward delay
+.sp
+\fBrequired\fP: False
+.sp
+\fBdefault\fP: 15
+.INDENT 0.0
+.TP
+.B \fBexample\fP:
+bridge\-fd 15
+.UNINDENT
+.UNINDENT
+.UNINDENT
+.sp
+\fBbridge\-ageing\fP
+.INDENT 0.0
+.INDENT 3.5
+\fBhelp\fP: bridge ageing
+.sp
+\fBrequired\fP: False
+.sp
+\fBdefault\fP: 300
+.INDENT 0.0
+.TP
+.B \fBexample\fP:
+bridge\-ageing 300
+.UNINDENT
+.UNINDENT
+.UNINDENT
+.sp
+\fBbridge\-hello\fP
+.INDENT 0.0
+.INDENT 3.5
+\fBhelp\fP: bridge set hello time
+.sp
+\fBrequired\fP: False
+.sp
+\fBdefault\fP: 2
+.INDENT 0.0
+.TP
+.B \fBexample\fP:
+bridge\-hello 2
+.UNINDENT
+.UNINDENT
+.UNINDENT
+.sp
+\fBbridge\-mcquerier\fP
+.INDENT 0.0
+.INDENT 3.5
+\fBhelp\fP: set multicast querier
+.sp
+\fBrequired\fP: False
+.sp
+\fBdefault\fP: 0
+.INDENT 0.0
+.TP
+.B \fBexample\fP:
+bridge\-mcquerier 0
+.UNINDENT
+.UNINDENT
+.UNINDENT
+.sp
+\fBbridge\-mclmc\fP
+.INDENT 0.0
+.INDENT 3.5
+\fBhelp\fP: set multicast last member count
+.sp
+\fBrequired\fP: False
+.sp
+\fBdefault\fP: 2
+.INDENT 0.0
+.TP
+.B \fBexample\fP:
+bridge\-mclmc 2
+.UNINDENT
+.UNINDENT
+.UNINDENT
+.sp
+\fBbridge\-mcrouter\fP
+.INDENT 0.0
+.INDENT 3.5
+\fBhelp\fP: set multicast router
+.sp
+\fBrequired\fP: False
+.sp
+\fBdefault\fP: 1
+.INDENT 0.0
+.TP
+.B \fBexample\fP:
+bridge\-mcrouter 1
+.UNINDENT
+.UNINDENT
+.UNINDENT
+.sp
+\fBbridge\-portmcrouter\fP
+.INDENT 0.0
+.INDENT 3.5
+\fBhelp\fP: set port multicast routers
+.sp
+\fBrequired\fP: False
+.sp
+\fBdefault\fP: 1
+.INDENT 0.0
+.TP
+.B \fBexample\fP:
+bridge\-portmcrouter swp1=1 swp2=1
+.UNINDENT
+.UNINDENT
+.UNINDENT
+.sp
+\fBbridge\-mclmi\fP
+.INDENT 0.0
+.INDENT 3.5
+\fBhelp\fP: set multicast last member interval (in secs)
+.sp
+\fBrequired\fP: False
+.sp
+\fBdefault\fP: 1
+.INDENT 0.0
+.TP
+.B \fBexample\fP:
+bridge\-mclmi 1
+.UNINDENT
+.UNINDENT
+.UNINDENT
+.sp
+\fBbridge\-hashmax\fP
+.INDENT 0.0
+.INDENT 3.5
+\fBhelp\fP: set hash max
+.sp
+\fBrequired\fP: False
+.sp
+\fBdefault\fP: 4096
+.INDENT 0.0
+.TP
+.B \fBexample\fP:
+bridge\-hashmax 4096
+.UNINDENT
+.UNINDENT
+.UNINDENT
+.sp
+\fBbridge\-waitport\fP
+.INDENT 0.0
+.INDENT 3.5
+\fBhelp\fP: wait for a max of time secs for the specified ports
+to become available,if no ports are specified then those speci
+fied on bridge\-ports will be used here. Specifying no ports he
+re should not be used if we are using regex or "all" on bridge
+_ports,as it wouldnt work.
+.sp
+\fBrequired\fP: False
+.sp
+\fBdefault\fP: 0
+.INDENT 0.0
+.TP
+.B \fBexample\fP:
+bridge\-waitport 4
+.UNINDENT
+.UNINDENT
+.UNINDENT
+.sp
+\fBbridge\-mcqri\fP
+.INDENT 0.0
+.INDENT 3.5
+\fBhelp\fP: set multicast query response interval (in secs)
+.sp
+\fBrequired\fP: False
+.sp
+\fBdefault\fP: 10
+.INDENT 0.0
+.TP
+.B \fBexample\fP:
+bridge\-mcqri 10
+.UNINDENT
+.UNINDENT
+.UNINDENT
+.sp
+\fBbridge\-hashel\fP
+.INDENT 0.0
+.INDENT 3.5
+\fBhelp\fP: set hash elasticity
+.sp
+\fBrequired\fP: False
+.sp
+\fBdefault\fP: 4096
+.INDENT 0.0
+.TP
+.B \fBexample\fP:
+bridge\-hashel 4096
+.UNINDENT
+.UNINDENT
+.UNINDENT
+.sp
+\fBbridge\-mcqpi\fP
+.INDENT 0.0
+.INDENT 3.5
+\fBhelp\fP: set multicast querier interval (in secs)
+.sp
+\fBrequired\fP: False
+.sp
+\fBdefault\fP: 255
+.INDENT 0.0
+.TP
+.B \fBexample\fP:
+bridge\-mcqpi 255
+.UNINDENT
+.UNINDENT
+.UNINDENT
+.sp
+\fBbridge\-bridgeprio\fP
+.INDENT 0.0
+.INDENT 3.5
+\fBhelp\fP: bridge priority
+.sp
+\fBrequired\fP: False
+.sp
+\fBdefault\fP: 32768
+.INDENT 0.0
+.TP
+.B \fBexample\fP:
+bridge\-bridgeprio 32768
+.UNINDENT
+.UNINDENT
+.UNINDENT
+.sp
+\fBbridge\-maxage\fP
+.INDENT 0.0
+.INDENT 3.5
+\fBhelp\fP: bridge set maxage
+.sp
+\fBrequired\fP: False
+.sp
+\fBdefault\fP: 20
+.INDENT 0.0
+.TP
+.B \fBexample\fP:
+bridge\-maxage 20
+.UNINDENT
+.UNINDENT
+.UNINDENT
+.sp
+\fBbridge\-portmcfl\fP
+.INDENT 0.0
+.INDENT 3.5
+\fBhelp\fP: port multicast fast leave
+.sp
+\fBrequired\fP: False
+.sp
+\fBdefault\fP: 0
+.INDENT 0.0
+.TP
+.B \fBexample\fP:
+bridge\-portmcfl swp1=0 swp2=0
+.UNINDENT
+.UNINDENT
+.UNINDENT
+.sp
+\fBbridge\-mcqi\fP
+.INDENT 0.0
+.INDENT 3.5
+\fBhelp\fP: set multicast query interval (in secs)
+.sp
+\fBrequired\fP: False
+.sp
+\fBdefault\fP: 125
+.INDENT 0.0
+.TP
+.B \fBexample\fP:
+bridge\-mcqi 125
+.UNINDENT
+.UNINDENT
+.UNINDENT
+.UNINDENT
+.UNINDENT
+.sp
+\fBusercmds\fP: user commands for interfaces
+.INDENT 0.0
+.INDENT 3.5
+\fBdown\fP
+.INDENT 0.0
+.INDENT 3.5
+\fBhelp\fP: run command at interface down
+.sp
+\fBrequired\fP: False
+.UNINDENT
+.UNINDENT
+.sp
+\fBpost\-up\fP
+.INDENT 0.0
+.INDENT 3.5
+\fBhelp\fP: run command after interface bring up
+.sp
+\fBrequired\fP: False
+.UNINDENT
+.UNINDENT
+.sp
+\fBup\fP
+.INDENT 0.0
+.INDENT 3.5
+\fBhelp\fP: run command at interface bring up
+.sp
+\fBrequired\fP: False
+.UNINDENT
+.UNINDENT
+.sp
+\fBpre\-down\fP
+.INDENT 0.0
+.INDENT 3.5
+\fBhelp\fP: run command before bringing the interface down
+.sp
+\fBrequired\fP: False
+.UNINDENT
+.UNINDENT
+.sp
+\fBpre\-up\fP
+.INDENT 0.0
+.INDENT 3.5
+\fBhelp\fP: run command before bringing the interface up
+.sp
+\fBrequired\fP: False
+.UNINDENT
+.UNINDENT
+.sp
+\fBpost\-down\fP
+.INDENT 0.0
+.INDENT 3.5
+\fBhelp\fP: run command after bringing interface down
+.sp
+\fBrequired\fP: False
+.UNINDENT
+.UNINDENT
+.UNINDENT
+.UNINDENT
+.sp
+\fBmstpctl\fP: mstp configuration module for bridges
+.INDENT 0.0
+.INDENT 3.5
+\fBmstpctl\-fdelay\fP
+.INDENT 0.0
+.INDENT 3.5
+\fBhelp\fP: set forwarding delay
+.sp
+\fBrequired\fP: False
+.sp
+\fBdefault\fP: 15
+.INDENT 0.0
+.TP
+.B \fBexample\fP:
+mstpctl\-fdelay 15
+.UNINDENT
+.UNINDENT
+.UNINDENT
+.sp
+\fBmstpctl\-txholdcount\fP
+.INDENT 0.0
+.INDENT 3.5
+\fBhelp\fP: bridge transmit holdcount
+.sp
+\fBrequired\fP: False
+.sp
+\fBdefault\fP: 6
+.INDENT 0.0
+.TP
+.B \fBexample\fP:
+mstpctl\-txholdcount 6
+.UNINDENT
+.UNINDENT
+.UNINDENT
+.sp
+\fBmstpctl\-portautoedge\fP
+.INDENT 0.0
+.INDENT 3.5
+\fBhelp\fP: enable/disable auto transition to/from edge state of
+the port
+.sp
+\fBrequired\fP: False
+.sp
+\fBdefault\fP: no
+.sp
+\fBvalidvals\fP: yes,no
+.INDENT 0.0
+.TP
+.B \fBexample\fP:
+mstpctl\-portautoedge swp1=yes swp2=yes
+.UNINDENT
+.UNINDENT
+.UNINDENT
+.sp
+\fBmstpctl\-portrestrrole\fP
+.INDENT 0.0
+.INDENT 3.5
+\fBhelp\fP: enable/disable port ability to take root role of the
+port
+.sp
+\fBrequired\fP: False
+.sp
+\fBdefault\fP: no
+.sp
+\fBvalidvals\fP: yes,no
+.INDENT 0.0
+.TP
+.B \fBexample\fP:
+mstpctl\-portrestrrole swp1=no swp2=no
+.UNINDENT
+.UNINDENT
+.UNINDENT
+.sp
+\fBmstpctl\-portnetwork\fP
+.INDENT 0.0
+.INDENT 3.5
+\fBhelp\fP: enable/disable bridge assurance capability for a por
+t
+.sp
+\fBrequired\fP: False
+.sp
+\fBdefault\fP: no
+.sp
+\fBvalidvals\fP: yes,no
+.INDENT 0.0
+.TP
+.B \fBexample\fP:
+mstpctl\-portnetwork swp1=no swp2=no
+.UNINDENT
+.UNINDENT
+.UNINDENT
+.sp
+\fBmstpctl\-portp2p\fP
+.INDENT 0.0
+.INDENT 3.5
+\fBhelp\fP: bridge port p2p detection mode
+.sp
+\fBrequired\fP: False
+.sp
+\fBdefault\fP: no
+.sp
+\fBvalidvals\fP: yes,no
+.INDENT 0.0
+.TP
+.B \fBexample\fP:
+mstpctl\-portp2p swp1=no swp2=no
+.UNINDENT
+.UNINDENT
+.UNINDENT
+.sp
+\fBmstpctl\-treeprio\fP
+.INDENT 0.0
+.INDENT 3.5
+\fBhelp\fP: tree priority
+.sp
+\fBrequired\fP: False
+.sp
+\fBdefault\fP: 32768
+.sp
+validrange: 0\-65535
+.INDENT 0.0
+.TP
+.B \fBexample\fP:
+mstpctl\-treeprio 32768
+.UNINDENT
+.UNINDENT
+.UNINDENT
+.sp
+\fBmstpctl\-treeportprio\fP
+.INDENT 0.0
+.INDENT 3.5
+\fBhelp\fP: port priority for MSTI instance
+.sp
+\fBrequired\fP: False
+.sp
+\fBdefault\fP: 128
+.sp
+validrange: 0\-240
+.INDENT 0.0
+.TP
+.B \fBexample\fP:
+mstpctl\-treeportprio swp1=128 swp2=128
+.UNINDENT
+.UNINDENT
+.UNINDENT
+.sp
+\fBmstpctl\-hello\fP
+.INDENT 0.0
+.INDENT 3.5
+\fBhelp\fP: set hello time
+.sp
+\fBrequired\fP: False
+.sp
+\fBdefault\fP: 2
+.INDENT 0.0
+.TP
+.B \fBexample\fP:
+mstpctl\-hello 2
+.UNINDENT
+.UNINDENT
+.UNINDENT
+.sp
+\fBmstpctl\-ageing\fP
+.INDENT 0.0
+.INDENT 3.5
+\fBhelp\fP: ageing time
+.sp
+\fBrequired\fP: False
+.sp
+\fBdefault\fP: 300
+.INDENT 0.0
+.TP
+.B \fBexample\fP:
+mstpctl\-ageing 300
+.UNINDENT
+.UNINDENT
+.UNINDENT
+.sp
+\fBmstpctl\-portadminedge\fP
+.INDENT 0.0
+.INDENT 3.5
+\fBhelp\fP: enable/disable initial edge state of the port
+.sp
+\fBrequired\fP: False
+.sp
+\fBdefault\fP: no
+.sp
+\fBvalidvals\fP: yes,no
+.INDENT 0.0
+.TP
+.B \fBexample\fP:
+mstpctl\-portadminedge swp1=no swp2=no
+.UNINDENT
+.UNINDENT
+.UNINDENT
+.sp
+\fBmstpctl\-maxage\fP
+.INDENT 0.0
+.INDENT 3.5
+\fBhelp\fP: max message age
+.sp
+\fBrequired\fP: False
+.sp
+\fBdefault\fP: 20
+.INDENT 0.0
+.TP
+.B \fBexample\fP:
+mstpctl\-maxage 20
+.UNINDENT
+.UNINDENT
+.UNINDENT
+.sp
+\fBmstpctl\-maxhops\fP
+.INDENT 0.0
+.INDENT 3.5
+\fBhelp\fP: bridge max hops
+.sp
+\fBrequired\fP: False
+.sp
+\fBdefault\fP: 15
+.INDENT 0.0
+.TP
+.B \fBexample\fP:
+mstpctl\-maxhops 15
+.UNINDENT
+.UNINDENT
+.UNINDENT
+.sp
+\fBmstpctl\-portrestrtcn\fP
+.INDENT 0.0
+.INDENT 3.5
+\fBhelp\fP: enable/disable port ability to propagate received to
+pology change notification of the port
+.sp
+\fBrequired\fP: False
+.sp
+\fBdefault\fP: no
+.sp
+\fBvalidvals\fP: yes,no
+.INDENT 0.0
+.TP
+.B \fBexample\fP:
+mstpctl\-portrestrtcn swp1=no swp2=no
+.UNINDENT
+.UNINDENT
+.UNINDENT
+.sp
+\fBmstpctl\-portpathcost\fP
+.INDENT 0.0
+.INDENT 3.5
+\fBhelp\fP: bridge port path cost
+.sp
+\fBrequired\fP: False
+.sp
+\fBdefault\fP: 0
+.INDENT 0.0
+.TP
+.B \fBexample\fP:
+mstpctl\-portpathcost swp1=0 swp2=1
+.UNINDENT
+.UNINDENT
+.UNINDENT
+.sp
+\fBmstpctl\-portadminage\fP
+.INDENT 0.0
+.INDENT 3.5
+\fBhelp\fP: bridge port admin age
+.sp
+\fBrequired\fP: False
+.sp
+\fBdefault\fP: no
+.sp
+\fBvalidvals\fP: yes,no
+.INDENT 0.0
+.TP
+.B \fBexample\fP:
+mstpctl\-portadminage swp1=no swp2=no
+.UNINDENT
+.UNINDENT
+.UNINDENT
+.sp
+\fBmstpctl\-portbpdufilter\fP
+.INDENT 0.0
+.INDENT 3.5
+\fBhelp\fP: enable/disable bpdu filter on a port
+.sp
+\fBrequired\fP: False
+.sp
+\fBdefault\fP: no
+.sp
+\fBvalidvals\fP: yes,no
+.INDENT 0.0
+.TP
+.B \fBexample\fP:
+mstpctl\-portbpdufilter swp1=no swp2=no
+.UNINDENT
+.UNINDENT
+.UNINDENT
+.sp
+\fBmstpctl\-forcevers\fP
+.INDENT 0.0
+.INDENT 3.5
+\fBhelp\fP: bridge force stp version
+.sp
+\fBrequired\fP: False
+.sp
+\fBdefault\fP: rstp
+.INDENT 0.0
+.TP
+.B \fBexample\fP:
+mstpctl\-forcevers rstp
+.UNINDENT
+.UNINDENT
+.UNINDENT
+.sp
+\fBmstpctl\-treeportcost\fP
+.INDENT 0.0
+.INDENT 3.5
+\fBhelp\fP: port tree cost
+.sp
+\fBrequired\fP: False
+.UNINDENT
+.UNINDENT
+.sp
+\fBmstpctl\-bpduguard\fP
+.INDENT 0.0
+.INDENT 3.5
+\fBhelp\fP: enable/disable bpduguard
+.sp
+\fBrequired\fP: False
+.sp
+\fBdefault\fP: no
+.sp
+\fBvalidvals\fP: yes,no
+.INDENT 0.0
+.TP
+.B \fBexample\fP:
+mstpctl\-bpduguard swp1=no swp2=no
+.UNINDENT
+.UNINDENT
+.UNINDENT
+.UNINDENT
+.UNINDENT
+.sp
+\fBvlan\fP: vlan module configures vlan interfaces.This module under
+stands vlan interfaces with dot notations. eg swp1.100. Vlan inter
+faces with any other names need to have raw device and vlan id att
+ributes
+.INDENT 0.0
+.INDENT 3.5
+\fBvlan\-id\fP
+.INDENT 0.0
+.INDENT 3.5
+\fBhelp\fP: vlan id
+.sp
+\fBrequired\fP: False
+.UNINDENT
+.UNINDENT
+.sp
+\fBvlan\-raw\-device\fP
+.INDENT 0.0
+.INDENT 3.5
+\fBhelp\fP: vlan raw device
+.sp
+\fBrequired\fP: False
+.UNINDENT
+.UNINDENT
+.UNINDENT
+.UNINDENT
+.sp
+\fBifenslave\fP: bond configuration module
+.INDENT 0.0
+.INDENT 3.5
+\fBbond\-miimon\fP
+.INDENT 0.0
+.INDENT 3.5
+\fBhelp\fP: bond miimon
+.sp
+\fBrequired\fP: False
+.sp
+\fBdefault\fP: 0
+.sp
+validrange: 0\-255
+.INDENT 0.0
+.TP
+.B \fBexample\fP:
+bond\-miimon 0
+.UNINDENT
+.UNINDENT
+.UNINDENT
+.sp
+\fBbond\-slaves\fP
+.INDENT 0.0
+.INDENT 3.5
+\fBhelp\fP: bond slaves
+.sp
+\fBrequired\fP: True
+.INDENT 0.0
+.TP
+.B \fBexample\fP:
+bond\-slaves swp1 swp2
+.sp
+bond\-slaves glob swp1\-2
+.sp
+bond\-slaves regex (swp[1|2)
+.UNINDENT
+.UNINDENT
+.UNINDENT
+.sp
+\fBbond\-mode\fP
+.INDENT 0.0
+.INDENT 3.5
+\fBhelp\fP: bond mode
+.sp
+\fBrequired\fP: False
+.sp
+\fBdefault\fP: balance\-rr
+.sp
+\fBvalidvals\fP: balance\-rr,active\-backup,balance\-xor,broadcast,802.3ad,balance\-tlb,balance\-alb
+.INDENT 0.0
+.TP
+.B \fBexample\fP:
+bond\-mode 802.3ad
+.UNINDENT
+.UNINDENT
+.UNINDENT
+.sp
+\fBbond\-num\-grat\-arp\fP
+.INDENT 0.0
+.INDENT 3.5
+\fBhelp\fP: bond use carrier
+.sp
+\fBrequired\fP: False
+.sp
+\fBdefault\fP: 1
+.sp
+validrange: 0\-255
+.INDENT 0.0
+.TP
+.B \fBexample\fP:
+bond\-num\-grat\-arp 1
+.UNINDENT
+.UNINDENT
+.UNINDENT
+.sp
+\fBbond\-ad\-sys\-mac\-addr\fP
+.INDENT 0.0
+.INDENT 3.5
+\fBhelp\fP: 802.3ad system mac address
+.sp
+\fBrequired\fP: False
+.sp
+\fBdefault\fP: 00:00:00:00:00:00
+.INDENT 0.0
+.TP
+.B \fBexample\fP:
+bond\-ad\-sys\-mac\-addr 00:00:00:00:00:00
+.UNINDENT
+.UNINDENT
+.UNINDENT
+.sp
+\fBbond\-use\-carrier\fP
+.INDENT 0.0
+.INDENT 3.5
+\fBhelp\fP: bond use carrier
+.sp
+\fBrequired\fP: False
+.sp
+\fBdefault\fP: 1
+.sp
+\fBvalidvals\fP: 0,1
+.INDENT 0.0
+.TP
+.B \fBexample\fP:
+bond\-use\-carrier 1
+.UNINDENT
+.UNINDENT
+.UNINDENT
+.sp
+\fBbond\-lacp\-rate\fP
+.INDENT 0.0
+.INDENT 3.5
+\fBhelp\fP: bond use carrier
+.sp
+\fBrequired\fP: False
+.sp
+\fBdefault\fP: 0
+.sp
+\fBvalidvals\fP: 0,1
+.INDENT 0.0
+.TP
+.B \fBexample\fP:
+bond\-lacp\-rate 0
+.UNINDENT
+.UNINDENT
+.UNINDENT
+.sp
+\fBbond\-min\-links\fP
+.INDENT 0.0
+.INDENT 3.5
+\fBhelp\fP: bond min links
+.sp
+\fBrequired\fP: False
+.sp
+\fBdefault\fP: 0
+.INDENT 0.0
+.TP
+.B \fBexample\fP:
+bond\-min\-links 0
+.UNINDENT
+.UNINDENT
+.UNINDENT
+.sp
+\fBbond\-num\-unsol\-na\fP
+.INDENT 0.0
+.INDENT 3.5
+\fBhelp\fP: bond slave devices
+.sp
+\fBrequired\fP: False
+.sp
+\fBdefault\fP: 1
+.sp
+validrange: 0\-255
+.INDENT 0.0
+.TP
+.B \fBexample\fP:
+bond\-num\-unsol\-na 1
+.UNINDENT
+.UNINDENT
+.UNINDENT
+.sp
+\fBbond\-ad\-sys\-priority\fP
+.INDENT 0.0
+.INDENT 3.5
+\fBhelp\fP: 802.3ad system priority
+.sp
+\fBrequired\fP: False
+.sp
+\fBdefault\fP: 65535
+.INDENT 0.0
+.TP
+.B \fBexample\fP:
+bond\-ad\-sys\-priority 65535
+.UNINDENT
+.UNINDENT
+.UNINDENT
+.sp
+\fBbond\-xmit\-hash\-policy\fP
+.INDENT 0.0
+.INDENT 3.5
+\fBhelp\fP: bond slave devices
+.sp
+\fBrequired\fP: False
+.sp
+\fBdefault\fP: layer2
+.sp
+\fBvalidvals\fP: layer2,layer3+4,layer2+3
+.INDENT 0.0
+.TP
+.B \fBexample\fP:
+bond\-xmit\-hash\-policy layer2
+.UNINDENT
+.UNINDENT
+.UNINDENT
+.UNINDENT
+.UNINDENT
+.sp
+\fBaddress\fP: address configuration module for interfaces
+.INDENT 0.0
+.INDENT 3.5
+\fBbroadcast\fP
+.INDENT 0.0
+.INDENT 3.5
+\fBhelp\fP: broadcast address
+.sp
+\fBrequired\fP: False
+.INDENT 0.0
+.TP
+.B \fBexample\fP:
+broadcast 10.0.1.255
+.UNINDENT
+.UNINDENT
+.UNINDENT
+.sp
+\fBhwaddress\fP
+.INDENT 0.0
+.INDENT 3.5
+\fBhelp\fP: hw address
+.sp
+\fBrequired\fP: False
+.INDENT 0.0
+.TP
+.B \fBexample\fP:
+hwaddress 44:38:39:00:27:b8
+.UNINDENT
+.UNINDENT
+.UNINDENT
+.sp
+\fBalias\fP
+.INDENT 0.0
+.INDENT 3.5
+\fBhelp\fP: description/alias
+.sp
+\fBrequired\fP: False
+.INDENT 0.0
+.TP
+.B \fBexample\fP:
+alias testnetwork
+.UNINDENT
+.UNINDENT
+.UNINDENT
+.sp
+\fBaddress\fP
+.INDENT 0.0
+.INDENT 3.5
+\fBhelp\fP: ipv4 or ipv6 addresses
+.sp
+\fBrequired\fP: False
+.INDENT 0.0
+.TP
+.B \fBexample\fP:
+address 10.0.12.3/24
+.sp
+address 2000:1000:1000:1000:3::5/128
+.UNINDENT
+.UNINDENT
+.UNINDENT
+.sp
+\fBscope\fP
+.INDENT 0.0
+.INDENT 3.5
+\fBhelp\fP: scope
+.sp
+\fBrequired\fP: False
+.INDENT 0.0
+.TP
+.B \fBexample\fP:
+scope host
+.UNINDENT
+.UNINDENT
+.UNINDENT
+.sp
+\fBpreferred\-lifetime\fP
+.INDENT 0.0
+.INDENT 3.5
+\fBhelp\fP: preferred lifetime
+.sp
+\fBrequired\fP: False
+.INDENT 0.0
+.TP
+.B \fBexample\fP:
+preferred\-lifetime forever
+.sp
+preferred\-lifetime 10
+.UNINDENT
+.UNINDENT
+.UNINDENT
+.sp
+\fBgateway\fP
+.INDENT 0.0
+.INDENT 3.5
+\fBhelp\fP: default gateway
+.sp
+\fBrequired\fP: False
+.INDENT 0.0
+.TP
+.B \fBexample\fP:
+gateway 255.255.255.0
+.UNINDENT
+.UNINDENT
+.UNINDENT
+.sp
+\fBmtu\fP
+.INDENT 0.0
+.INDENT 3.5
+\fBhelp\fP: interface mtu
+.sp
+\fBrequired\fP: False
+.sp
+\fBdefault\fP: 1500
+.INDENT 0.0
+.TP
+.B \fBexample\fP:
+mtu 1600
+.UNINDENT
+.UNINDENT
+.UNINDENT
+.UNINDENT
+.UNINDENT
+.UNINDENT
+.UNINDENT
+.SH SEE ALSO
+.INDENT 0.0
+.INDENT 3.5
+interfaces(5),
+ifup(8),
+ip(8),
+mstpctl(8),
+brctl(8),
+ethtool(8)
+.UNINDENT
+.UNINDENT
+.SH AUTHOR
+roopa@cumulusnetworks.com
+.SH COPYRIGHT
+Copyright 2013 Cumulus Networks, Inc.  All rights reserved.
+.\" Generated by docutils manpage writer.
+.\" 
+.
diff --git a/man/interfaces.5 b/man/interfaces.5
new file mode 100644 (file)
index 0000000..68f7d48
--- /dev/null
@@ -0,0 +1,207 @@
+.\" Man page generated from reStructeredText.
+.
+.TH INTERFACES 5 "2014-02-05" "0.1" ""
+.SH NAME
+interfaces \- network interface configuration for ifupdown
+.
+.nr rst2man-indent-level 0
+.
+.de1 rstReportMargin
+\\$1 \\n[an-margin]
+level \\n[rst2man-indent-level]
+level margin: \\n[rst2man-indent\\n[rst2man-indent-level]]
+-
+\\n[rst2man-indent0]
+\\n[rst2man-indent1]
+\\n[rst2man-indent2]
+..
+.de1 INDENT
+.\" .rstReportMargin pre:
+. RS \\$1
+. nr rst2man-indent\\n[rst2man-indent-level] \\n[an-margin]
+. nr rst2man-indent-level +1
+.\" .rstReportMargin post:
+..
+.de UNINDENT
+. RE
+.\" indent \\n[an-margin]
+.\" old: \\n[rst2man-indent\\n[rst2man-indent-level]]
+.nr rst2man-indent-level -1
+.\" new: \\n[rst2man-indent\\n[rst2man-indent-level]]
+.in \\n[rst2man-indent\\n[rst2man-indent-level]]u
+..
+.SH DESCRIPTION
+.INDENT 0.0
+.INDENT 3.5
+\fB/etc/network/interfaces\fP contains network interface configuration
+information for the \fBifup(8)\fP, \fBifdown(8)\fP and \fBifquery(8)\fP commands.
+.sp
+This is where you configure how your system is connected to the network.
+.sp
+Lines starting with # are ignored. Note that end\-of\-line comments are
+NOT supported, comments must be on a line of their own.
+.sp
+A line may be extended across multiple lines by making the last character
+a backslash.
+.sp
+The file consists of zero or more "iface", "auto",  "allow\-"
+and "source" stanzas. Here is an example:
+.sp
+.nf
+.ft C
+auto lo eth0
+allow\-hotplug eth1
+
+iface lo inet loopback
+
+source /etc/network/interfaces.d/bridges
+
+iface eth0 inet static
+    address 192.168.1.1/24
+    up flush\-mail
+
+iface eth1 inet dhcp
+.ft P
+.fi
+.sp
+Lines beginning with the word "auto" are used to identify the physical
+interfaces to be brought up when ifup is run with the \-a option.
+(This option is used by the system boot scripts.) Physical interface names
+should follow the word "auto" on the same line.  There can be  multiple
+"auto"  stanzas.
+.sp
+Lines beginning with "allow\-" are  used  to  identify  interfaces  that
+should  be  brought  up automatically by various subsytems. This may be
+done using a command such as "ifup \-\-allow=hotplug  eth0  eth1",  which
+will  only  bring up eth0 or eth1 if it is listed in an "allow\-hotplug"
+line. Note that "allow\-auto" and "auto" are synonyms.
+.sp
+Lines beginning with "source" are used to include  stanzas  from  other
+files, so configuration can be split into many files. The word "source"
+is followed by the path of file to be sourced. Shell wildcards  can  be
+used. Currently only supports absolute
+path names.
+.sp
+iface is normally given a interface name as its first non\-option
+argument.
+.sp
+The interface name is followed by the name of the address family that the
+interface uses. This will be "inet" for TCP/IP networking and inet6 for
+ipv6. Following that is the name of the method used to configure the
+interface.
+.sp
+ifupdown supports iface stanzas without a family or a method. This enables
+using the same stanza for inet and inet6 family addresses. And the method
+defaults to "static"
+.sp
+Additional interface options/attributes can be given on subsequent lines
+in the iface stanza. These options come from addon modules. see
+\fBifupdown\-addons\-interfaces(5)\fP for these options.
+.sp
+example bridge interface with additional attributes listed in the
+\fBifupdown\-addons\-interfaces(5)\fP man page:
+.sp
+.nf
+.ft C
+auto br0
+iface br0
+    address 12.0.0.4/24
+    address 2000:1000:1000:1000:3::5/128
+    bridge\-ports swp1 swp2 swp3
+    bridge\-stp on
+.ft P
+.fi
+.sp
+ifupdown supports python\-mako style templates in the interfaces file.
+See examples section for details.
+.sp
+See \fB/usr/share/doc/python\-ifupdown2/examples/\fP for \fBinterfaces(5)\fP
+file examples and interfaces file generation scripts.
+.UNINDENT
+.UNINDENT
+.SH METHODS
+.INDENT 0.0
+.INDENT 3.5
+Both \fBinet\fP and \fBinet6\fP address family interfaces can use the following
+methods (However they are not required):
+.INDENT 0.0
+.TP
+.B The loopback Method
+This method may be used to define the loopback interface.
+.TP
+.B The static Method
+This method may be used to define ethernet interfaces with
+statically allocated addresses.
+.TP
+.B The dhcp Method
+This method may be used to obtain an address via DHCP.
+.UNINDENT
+.UNINDENT
+.UNINDENT
+.SH BUILTIN INTERFACES
+.INDENT 0.0
+.INDENT 3.5
+\fBiface\fP sections for some interfaces like physical interfaces or vlan
+interfaces in dot notation (like eth1.100) are understood by ifupdown.
+These interfaces do not need an entry in the interfaces file if
+they are dependents of other interfaces and dont need any specific
+configurations like addresses etc.
+.UNINDENT
+.UNINDENT
+.SH EXAMPLES
+.INDENT 0.0
+.INDENT 3.5
+Sample /etc/network/interfaces file:
+.sp
+.nf
+.ft C
+auto lo
+iface lo
+    address 192.168.2.0/24
+    address 2001:dee:eeee:1::4/128
+
+auto eth0
+iface eth0 inet dhcp
+
+auto eth1
+iface eth1 inet manual
+    address 192.168.2.0/24
+    address 2001:dee:eeee:1::4/128
+
+# source files from a directory /etc/network/interfaces.d
+source /etc/network/interfaces.d/*
+
+# Using mako style templates
+% for v in [11,12]:
+    auto vlan${v}
+    iface vlan${v} inet static
+        address 10.20.${v}.3/24
+% endfor
+.ft P
+.fi
+.sp
+For additional syntax and examples see \fBifupdown\-addons\-interfaces(5)\fP
+.UNINDENT
+.UNINDENT
+.SH FILES
+.INDENT 0.0
+.INDENT 3.5
+/etc/network/interfaces
+.UNINDENT
+.UNINDENT
+.SH SEE ALSO
+.INDENT 0.0
+.INDENT 3.5
+ifupdown\-addons\-interfaces(5),
+ifup(8),
+ifquery(8),
+ifreload(8)
+.UNINDENT
+.UNINDENT
+.SH AUTHOR
+Roopa Prabhu <roopa@cumulusnetworks.com>
+.SH COPYRIGHT
+Copyright 2014 Cumulus Networks, Inc.  All rights reserved.
+.\" Generated by docutils manpage writer.
+.\" 
+.
diff --git a/sbin/ifupdown b/sbin/ifupdown
new file mode 100755 (executable)
index 0000000..d6bdeb2
--- /dev/null
@@ -0,0 +1,496 @@
+#!/usr/bin/python
+#
+# Copyright 2014 Cumulus Networks, Inc. All rights reserved.
+# Author: Roopa Prabhu, roopa@cumulusnetworks.com
+#
+# ifupdown --
+#    tool to configure network interfaces
+#
+import sys
+import os
+import argcomplete
+import argparse
+import ConfigParser
+import StringIO
+import logging
+import logging.handlers
+import resource
+from ifupdown.ifupdownmain import *
+from ifupdown.utils import *
+
+lockfile="/run/network/.lock"
+configfile="/etc/network/ifupdown2/ifupdown2.conf"
+configmap_g=None
+logger = None
+interfacesfileiobuf=None
+ENVPATH = "/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"
+
+def run_up(args):
+    logger.debug('args = %s' %str(args))
+
+    try:
+        iflist = args.iflist
+        if len(args.iflist) == 0:
+            iflist = None
+        logger.debug('creating ifupdown object ..')
+        cachearg=(False if (iflist or args.nocache or
+                            args.perfmode or args.noact)
+                            else True)
+        ifupdown_handle = ifupdownMain(config=configmap_g,
+                                       force=args.force,
+                                       withdepends=args.withdepends,
+                                       perfmode=args.perfmode,
+                                       dryrun=args.noact,
+                                       cache=cachearg,
+                                       addons_enable=not args.noaddons,
+                                       statemanager_enable=not args.noaddons,
+                                       interfacesfile=args.interfacesfile,
+                                       interfacesfileiobuf=interfacesfileiobuf,
+                                       interfacesfileformat=args.interfacesfileformat)
+        if args.noaddons:
+            ifupdown_handle.up(['up'], args.all, args.CLASS, iflist,
+                               excludepats=args.excludepats,
+                               printdependency=args.printdependency,
+                               syntaxcheck=args.syntaxcheck, type=args.type,
+                               skipupperifaces=args.skipupperifaces)
+        else:
+            ifupdown_handle.up(['pre-up', 'up', 'post-up'],
+                               args.all, args.CLASS, iflist,
+                               excludepats=args.excludepats,
+                               printdependency=args.printdependency,
+                               syntaxcheck=args.syntaxcheck, type=args.type,
+                               skipupperifaces=args.skipupperifaces)
+    except:
+        raise
+
+def run_down(args):
+    logger.debug('args = %s' %str(args))
+
+    try:
+        iflist = args.iflist
+        logger.debug('creating ifupdown object ..')
+        ifupdown_handle = ifupdownMain(config=configmap_g, force=args.force,
+                                       withdepends=args.withdepends,
+                                       perfmode=args.perfmode,
+                                       dryrun=args.noact,
+                                       addons_enable=not args.noaddons,
+                                       statemanager_enable=not args.noaddons,
+                                       interfacesfile=args.interfacesfile,
+                                       interfacesfileiobuf=interfacesfileiobuf,
+                                       interfacesfileformat=args.interfacesfileformat)
+
+        ifupdown_handle.down(['pre-down', 'down', 'post-down'],
+                             args.all, args.CLASS, iflist,
+                             excludepats=args.excludepats,
+                             printdependency=args.printdependency,
+                             usecurrentconfig=args.usecurrentconfig,
+                             type=args.type)
+    except:
+        raise
+
+def run_query(args):
+    logger.debug('args = %s' %str(args))
+
+    try:
+        iflist = args.iflist
+        if args.checkcurr:
+            qop='query-checkcurr'
+        elif args.running:
+            qop='query-running'
+        elif args.raw:
+            qop='query-raw'
+        elif args.syntaxhelp:
+            qop = 'query-syntax'
+        elif args.printdependency:
+            qop = 'query-dependency'
+        elif args.printsavedstate:
+            qop = 'query-savedstate'
+        else:
+            qop='query'
+        cachearg=(False if (iflist or args.nocache or
+                            args.perfmode or args.syntaxhelp or
+                            (qop != 'query-checkcurr' and
+                            qop != 'query-running')) else True)
+        if not iflist and qop == 'query-running':
+            iflist = [i for i in os.listdir('/sys/class/net/')
+                        if os.path.isdir('/sys/class/net/%s' %i)]
+        logger.debug('creating ifupdown object ..')
+        ifupdown_handle = ifupdownMain(config=configmap_g,
+                                       withdepends=args.withdepends,
+                                       perfmode=args.perfmode,
+                                       cache=cachearg,
+                                       interfacesfile=args.interfacesfile,
+                                       interfacesfileiobuf=interfacesfileiobuf,
+                                       interfacesfileformat=args.interfacesfileformat)
+
+        ifupdown_handle.query([qop], args.all, args.CLASS, iflist,
+                              excludepats=args.excludepats,
+                              printdependency=args.printdependency,
+                              format=args.format, type=args.type)
+    except:
+        raise
+
+def run_reload(args):
+    logger.debug('args = %s' %str(args))
+
+    try:
+        logger.debug('creating ifupdown object ..')
+        ifupdown_handle = ifupdownMain(config=configmap_g,
+                                       withdepends=args.withdepends,
+                                       perfmode=args.perfmode)
+        ifupdown_handle.reload(['pre-up', 'up', 'post-up'],
+                               ['pre-down', 'down', 'post-down'],
+                               auto=args.all, allow=None, ifacenames=None,
+                               excludepats=args.excludepats,
+                               usecurrentconfig=args.usecurrentconfig,
+                               currentlyup=args.currentlyup)
+    except:
+        raise
+
+def init(args):
+    global logger
+    global interfacesfileiobuf
+
+    log_level = logging.WARNING
+    if args.verbose:
+        log_level = logging.INFO
+    if args.debug:
+        log_level = logging.DEBUG
+
+    try:
+        if hasattr(args, 'syslog') and args.syslog:
+            root_logger = logging.getLogger()
+            syslog_handler = logging.handlers.SysLogHandler(address='/dev/log',
+                             facility=logging.handlers.SysLogHandler.LOG_DAEMON)
+            logging.addLevelName(logging.ERROR, 'error')
+            logging.addLevelName(logging.WARNING, 'warning')
+            logging.addLevelName(logging.DEBUG, 'debug')
+            logging.addLevelName(logging.INFO, 'info')
+            root_logger.setLevel(log_level)
+            syslog_handler.setFormatter(logging.Formatter(
+                '%(name)s: %(levelname)s: %(message)s'))
+            root_logger.addHandler(syslog_handler)
+            logger = logging.getLogger('ifupdown')
+        else:
+            logging.basicConfig(level=log_level,
+                format='%(levelname)s: %(message)s')
+            logging.addLevelName(logging.ERROR, 'error')
+            logging.addLevelName(logging.WARNING, 'warning')
+            logging.addLevelName(logging.DEBUG, 'debug')
+            logging.addLevelName(logging.INFO, 'info')
+            logger = logging.getLogger('ifupdown')
+    except:
+        raise
+
+    # If interfaces file is stdin, read
+    if hasattr(args, 'interfacesfile') and args.interfacesfile == '-':
+        interfacesfileiobuf = sys.stdin.read()
+
+def deinit():
+    {}
+
+def update_argparser(argparser):
+    """ base parser, common to all commands """
+
+    argparser.add_argument('-a', '--all', action='store_true', required=False,
+                help='process all interfaces marked \"auto\"')
+    argparser.add_argument('iflist', metavar='IFACE',
+                nargs='*', help='interface list separated by spaces. ' +
+                'IFACE list is mutually exclusive with -a option.')
+    argparser.add_argument('-v', '--verbose', dest='verbose',
+                action='store_true', help='verbose')
+    argparser.add_argument('-d', '--debug', dest='debug',
+                action='store_true',
+                help='output debug info')
+    argparser.add_argument('-q', '--quiet', dest='quiet',
+                action='store_true',
+                help=argparse.SUPPRESS)
+    argparser.add_argument('--allow', dest='CLASS', 
+                help='ignore non-\"allow-CLASS\" interfaces')
+    argparser.add_argument('-w', '--with-depends', dest='withdepends',
+                action='store_true', help='run with all dependent interfaces.'+
+                ' This option is redundant when \'-a\' is specified. With ' +
+                '\'-a\' interfaces are always executed in dependency order')
+    argparser.add_argument('--perfmode', dest='perfmode',
+                action='store_true', help=argparse.SUPPRESS)
+    #argparser.add_argument('-j', '--jobs', dest='jobs', type=int,
+    #            default=-1, choices=range(1,12), help=argparse.SUPPRESS)
+    argparser.add_argument('--nocache', dest='nocache', action='store_true',
+                help=argparse.SUPPRESS)
+    argparser.add_argument('-X', '--exclude', dest='excludepats',
+                action='append',
+                help='Exclude interfaces from the list of interfaces' +
+                ' to operate on. Can be specified multiple times.')
+    argparser.add_argument('-i', '--interfaces', dest='interfacesfile',
+                default='/etc/network/interfaces',
+                help='use interfaces file instead of default ' +
+                '/etc/network/interfaces')
+    argparser.add_argument('-t', '--interfaces-format',
+                dest='interfacesfileformat',
+                default='native',
+                choices=['native', 'json'],
+                help='interfaces file format')
+    argparser.add_argument('-T', '--type',
+                dest='type',
+                default=None,
+                choices=['iface', 'vlan'],
+                help='type of interface entry (iface or vlan).' +
+                     'This option can be used in case of ambiguity between ' +
+                     'a vlan interface and an iface interface of the same name')
+
+def update_ifupdown_argparser(argparser):
+    """ common arg parser for ifup and ifdown """
+    argparser.add_argument('-f', '--force', dest='force',
+                action='store_true',
+                help='force run all operations')
+    argparser.add_argument('-l', '--syslog', dest='syslog',
+                action='store_true',
+                help=argparse.SUPPRESS)
+    group = argparser.add_mutually_exclusive_group(required=False)
+    group.add_argument('-n', '--no-act', dest='noact',
+                action='store_true', help='print out what would happen,' +
+                'but don\'t do it')
+    group.add_argument('-p', '--print-dependency',
+                dest='printdependency', choices=['list', 'dot'],
+                help='print iface dependency')
+    group.add_argument('--no-scripts', '--admin-state',
+                dest='noaddons',  action='store_true',
+                help='dont run any addon modules/scripts. Only bring the ' +
+                    'interface administratively up/down')
+
+def update_ifup_argparser(argparser):
+    argparser.add_argument('-s', '--syntax-check', dest='syntaxcheck',
+                action='store_true',
+                help='Only run the interfaces file parser')
+    argparser.add_argument('-k', '--skip-upperifaces', dest='skipupperifaces',
+                action='store_true',
+                help='ifup by default tries to add newly created interfaces' +
+                ' into its upper/parent interfaces. Eg. if a bridge port is' +
+                ' created as a result of ifup on the port, ifup automatically' +
+                ' adds the port to the bridge. This option can be used to ' +
+                'disable this default behaviour')
+    update_ifupdown_argparser(argparser)
+
+def update_ifdown_argparser(argparser):
+    update_ifupdown_argparser(argparser)
+    argparser.add_argument('-u', '--use-current-config',
+                dest='usecurrentconfig',  action='store_true',
+                help='By default ifdown looks at the saved state for ' +
+                'interfaces to bring down. This option allows ifdown to ' +
+                'look at the current interfaces file. Useful when your ' +
+                'state file is corrupted or you want down to use the latest '
+                'from the interfaces file')
+
+def update_ifquery_argparser(argparser):
+    """ arg parser for ifquery options """
+
+    # -l is same as '-a', only here for backward compatibility
+    argparser.add_argument('-l', '--list', action='store_true', dest='all',
+                help=argparse.SUPPRESS)
+    group = argparser.add_mutually_exclusive_group(required=False)
+    group.add_argument('-r', '--running', dest='running',
+                       action='store_true',
+                       help='query running state of an interface')
+    group.add_argument('-c', '--check', dest='checkcurr',
+                       action='store_true',
+                       help='check interface file contents against ' +
+                       'running state of an interface')
+    group.add_argument('-x', '--raw', action='store_true', dest='raw',
+                       help='print raw config file entries')
+    group.add_argument('--print-savedstate', action='store_true',
+                       dest='printsavedstate',
+                       help=argparse.SUPPRESS)
+    argparser.add_argument('-o', '--format', dest='format', default='native',
+                           choices=['native', 'json'],
+                           help='interface display format')
+    argparser.add_argument('-p', '--print-dependency',
+                           dest='printdependency', choices=['list', 'dot'],
+                           help='print interface dependency')
+    argparser.add_argument('-s', '--syntax-help', action='store_true',
+                           dest='syntaxhelp',
+                           help='print supported interface config syntax')
+
+def update_ifreload_argparser(argparser):
+    """ parser for ifreload """
+    group = argparser.add_mutually_exclusive_group(required=True)
+    group.add_argument('-a', '--all', action='store_true',
+                help='process all interfaces marked \"auto\"')
+    group.add_argument('-c', '--currently-up', dest='currentlyup',
+                action='store_true',
+                help='only reload auto and other interfaces that are ' +
+                'currently up')
+    argparser.add_argument('iflist', metavar='IFACE',
+                nargs='*', help=argparse.SUPPRESS)
+    argparser.add_argument('-n', '--no-act', dest='noact',
+                action='store_true', help=argparse.SUPPRESS)
+    argparser.add_argument('-v', '--verbose', dest='verbose',
+                action='store_true', help='verbose')
+    argparser.add_argument('-d', '--debug', dest='debug',
+                action='store_true',
+                help='output debug info')
+    argparser.add_argument('-w', '--with-depends', dest='withdepends',
+                action='store_true', help=argparse.SUPPRESS)
+    argparser.add_argument('--perfmode', dest='perfmode',
+                action='store_true', help=argparse.SUPPRESS)
+    argparser.add_argument('--nocache', dest='nocache', action='store_true',
+                help=argparse.SUPPRESS)
+    argparser.add_argument('-X', '--exclude', dest='excludepats',
+                action='append',
+                help=argparse.SUPPRESS)
+    #argparser.add_argument('-j', '--jobs', dest='jobs', type=int,
+    #            default=-1, choices=range(1,12), help=argparse.SUPPRESS)
+    #argparser.add_argument('-i', '--interfaces', dest='interfacesfile',
+    #            default='/etc/network/interfaces',
+    #            help='use interfaces file instead of default ' +
+    #            '/etc/network/interfaces')
+    argparser.add_argument('-u', '--use-current-config',
+                dest='usecurrentconfig',  action='store_true',
+                help='By default ifreload looks at saved state for ' +
+                'interfaces to bring down. With this option ifreload will'
+                ' only look at the current interfaces file. Useful when your ' +
+                'state file is corrupted or you want down to use the latest '
+                'from the interfaces file')
+    argparser.add_argument('-l', '--syslog', dest='syslog',
+                action='store_true',
+                help=argparse.SUPPRESS)
+    argparser.add_argument('-f', '--force', dest='force',
+                action='store_true',
+                help='force run all operations')
+
+def parse_args(argsv, op):
+    if op == 'query':
+        descr = 'query interfaces (all or interface list)'
+    elif op == 'reload':
+        descr = 'reload interface configuration.'
+    else:
+        descr = 'interface management'
+    argparser = argparse.ArgumentParser(description=descr)
+    if op == 'reload':
+        update_ifreload_argparser(argparser)
+    else:
+        update_argparser(argparser)
+        if op == 'up':
+            update_ifup_argparser(argparser)
+        elif op == 'down':
+            update_ifdown_argparser(argparser)
+        elif op == 'query':
+            update_ifquery_argparser(argparser)
+        elif op == 'reload':
+            update_ifreload_argparser(argparser)
+    argcomplete.autocomplete(argparser)
+    return argparser.parse_args(argsv)
+
+handlers = {'up' : run_up,
+            'down' : run_down,
+            'query' : run_query,
+            'reload' : run_reload }
+
+def validate_args(op, args):
+    #if op == 'up' and args.syntaxcheck:
+    #    if args.iflist or args.all:
+    #        print 'ignoring interface options ..'
+    #    return True
+    if op == 'query' and args.syntaxhelp:
+        return True
+    if op == 'reload':
+        if not args.all and not args.currentlyup:
+            print '\'-a\' or \'-c\' option is required'
+            return False
+    elif (not args.iflist and
+            not args.all and not args.CLASS):
+        print '\'-a\' option or interface list are required'
+        return False
+    if args.iflist and args.all:
+        print '\'-a\' option and interface list are mutually exclusive'
+        return False
+    if op != 'reload' and args.CLASS and (args.all or args.iflist):
+        print ('\'--allow\' option is mutually exclusive ' +
+               'with interface list and \'-a\'')
+        return False
+    return True
+
+def read_config(args):
+    global configmap_g
+
+    config = open(configfile, 'r').read()
+    configStr = '[ifupdown2]\n' + config
+    configFP =  StringIO.StringIO(configStr)
+    parser = ConfigParser.RawConfigParser()
+    parser.readfp(configFP)
+    configmap_g = dict(parser.items('ifupdown2'))
+
+    # Preprocess config map
+    configval = configmap_g.get('multiple_vlan_aware_bridge_support', '0')
+    if configval == '0':
+        # if multiple bridges not allowed, set the bridge-vlan-aware
+        # attribute in the 'no_repeats' config, so that the ifupdownmain
+        # module can catch it appropriately
+        configmap_g['no_repeats'] = {'bridge-vlan-aware' : 'yes'}
+
+
+    configval = configmap_g.get('link_master_slave', '0')
+    if configval == '1':
+        # link_master_slave is only valid when all is set
+        if hasattr(args, 'all') and not args.all:
+            configmap_g['link_master_slave'] = '0'
+
+    configval = configmap_g.get('delay_admin_state_change', '0')
+    if configval == '1':
+        # reset link_master_slave if delay_admin_state_change is on
+        configmap_g['link_master_slave'] = '0'
+
+def main(argv):
+    """ main function """
+    args = None
+    try:
+        op = None
+        if argv[0].endswith('ifup'):
+            op = 'up'
+        elif argv[0].endswith('ifdown'):
+            op = 'down'
+        elif argv[0].endswith('ifquery'):
+            op = 'query'
+        elif argv[0].endswith('ifreload'):
+            op = 'reload'
+        else:
+            print ('Unexpected executable.' +
+                   ' Should be \'ifup\' or \'ifdown\' or \'ifquery\'')
+            exit(1)
+        # Command line arg parser
+        args = parse_args(argv[1:], op)
+        if not validate_args(op, args):
+            exit(1)
+
+        if not sys.argv[0].endswith('ifquery') and not os.geteuid() == 0:
+            print 'error: must be root to run this command'
+            exit(1)
+
+        if not sys.argv[0].endswith('ifquery') and not utils.lockFile(lockfile):
+            print 'Another instance of this program is already running.'
+            exit(0)
+
+        read_config(args)
+        init(args)
+        handlers.get(op)(args)
+    except Exception, e:
+        if not str(e):
+            exit(1)
+        if args and args.debug:
+            raise
+        else:
+            if logger:
+                logger.error(str(e))
+            else:
+                print str(e)
+            #if args and not args.debug:
+            #    print '\nrerun the command with \'-d\' for a detailed errormsg'
+        exit(1)
+    finally:
+        deinit()
+
+if __name__ == "__main__":
+
+    # required during boot
+    os.putenv('PATH', ENVPATH)
+    resource.setrlimit(resource.RLIMIT_CORE, (0,0))
+    main(sys.argv)
diff --git a/scripts/genmanpages.sh b/scripts/genmanpages.sh
new file mode 100755 (executable)
index 0000000..2553dc7
--- /dev/null
@@ -0,0 +1,28 @@
+#!/bin/sh
+#
+# Copyright 2013 Cumulus Networks, Inc.
+# All rights reserved.
+#
+
+# Install the man pages into the sysroot
+SRC_MAN_DIR=$1
+DST_MAN_DIR=$2
+
+echo -n "Generating man pages .."
+# Loop over all the man directories
+mkdir -p $DST_MAN_DIR
+for p in $(ls $SRC_MAN_DIR/*.rst) ; do
+    # strip src man path
+    src_file=$p
+    dst_file=${p##.*\/}
+    dst_file="${DST_MAN_DIR}/${dst_file%.rst}"
+    # treat warnings as errors
+    rst2man --halt=2 "$p" > $dst_file || {
+        echo
+        echo "Error: problems generating man page: $p"
+        rm -f $dst_file &>/dev/null
+        exit 1
+    }
+    echo -n "."
+done
+echo " done."
diff --git a/setup.py b/setup.py
new file mode 100755 (executable)
index 0000000..015a550
--- /dev/null
+++ b/setup.py
@@ -0,0 +1,47 @@
+from distutils.core import setup
+
+setup(name='ifupdown2',
+      version='0.1',
+      description = "ifupdown 2",
+      author='Roopa Prabhu',
+      author_email='roopa@cumulusnetworks.com',
+      url='cumulusnetworks.com',
+      packages=['ifupdown', 'ifupdownaddons'],
+      scripts = ['sbin/ifupdown'],
+      install_requires = ['python-gvgen', 'python-argcomplete', 'python-ipaddr'],
+      data_files=[('share/man/man8/',
+                      ['man/ifup.8', 'man/ifquery.8', 'man/ifreload.8']),
+                  ('share/man/man5/',
+                      ['man/interfaces.5', 'man/ifupdown-addons-interfaces.5']),
+                  ('/etc/init.d/',
+                      ['init.d/networking']),
+                  ('/sbin/', ['sbin/ifupdown']),
+                  ('/etc/network/ifupdown2/',
+                      ['config/ifupdown2.conf']),
+                  ('/etc/default/',
+                      ['config/networking']),
+                  ('/usr/share/python-ifupdown2/',
+                      ['docs/examples/generate_interfaces.py']),
+                  ('/usr/share/doc/python-ifupdown2/examples/',
+                      ['docs/examples/interfaces',
+                       'docs/examples/interfaces_bridge_template_func',
+                       'docs/examples/interfaces_with_template',
+                       'docs/examples/interfaces_bridge_igmp_mstp']),
+                  ('/usr/share/doc/python-ifupdown2/examples/vlan_aware_bridges',
+                      ['docs/examples/vlan_aware_bridges/interfaces.basic',
+                       'docs/examples/vlan_aware_bridges/interfaces.vlan_prune_and_access_ports',
+                       'docs/examples/vlan_aware_bridges/interfaces.with_bonds',
+                       'docs/examples/vlan_aware_bridges/interfaces.with_clag']),
+                  ('/etc/bash_completion.d/', ['completion/ifup']),
+                  ('/usr/share/ifupdownaddons/', ['addons/bridge.py',
+                      'addons/ifenslave.py', 'addons/vlan.py',
+                      'addons/mstpctl.py', 'addons/address.py',
+                      'addons/dhcp.py', 'addons/usercmds.py',
+                      'addons/ethtool.py', 'addons/loopback.py',
+                      'addons/addressvirtual.py', 'addons/vxlan.py',
+                      'addons/bridgevlan.py']),
+                  ('/var/lib/ifupdownaddons/', ['config/addons.conf']),
+                  ('/var/lib/ifupdownaddons/policy.d/', []),
+                  ('/etc/network/ifupdown2/policy.d/', [])
+                  ]
+      )
diff --git a/stdeb.cfg b/stdeb.cfg
new file mode 100644 (file)
index 0000000..db6414a
--- /dev/null
+++ b/stdeb.cfg
@@ -0,0 +1,2 @@
+[DEFAULT]
+Conflicts: ifupdown
diff --git a/tests/ifstatetest b/tests/ifstatetest
new file mode 100755 (executable)
index 0000000..a761e75
--- /dev/null
@@ -0,0 +1,56 @@
+#!/usr/bin/python
+
+""" test for testing and profiling state manager """
+
+import cProfile
+
+from ifupdown.networkinterfaces import *
+from ifupdown.iface import *
+from ifupdown.statemanager import pickling
+import os
+
+ifaceobjdict = {}
+state_file = '/tmp/ifstatetest'
+
+def save_iface(ifaceobj):
+    ifaceobjdict[ifaceobj.get_name()] = ifaceobj
+    
+def read_default_iface_config():
+    """ Reads default network interface config /etc/network/interfaces. """
+    nifaces = networkInterfaces()
+    nifaces.subscribe('iface_found', save_iface)
+    nifaces.load()
+
+def save_state():
+    try:
+        with open(state_file, 'w') as f:
+            for ifaceobj in ifaceobjdict.values():
+                pickling.save_obj(f, ifaceobj)
+    except:
+        raise
+
+def load_state():
+    global ifaceobjdict
+
+    if not os.path.exists(state_file):
+        return
+
+    del ifaceobjdict
+    ifaceobjdict = {}
+
+    # Read all ifaces from file
+    for ifaceobj in pickling.load(state_file):
+        save_iface(ifaceobj)
+
+
+print 'Reading iface config files ..'
+cProfile.run('read_default_iface_config()')
+print 'number of objects: %d' %len(ifaceobjdict)
+
+print 'saving iface state ..'
+cProfile.run('save_state()')
+
+print 'loading iface state ..'
+cProfile.run('load_state()')
+print 'number of objects: %d' %len(ifaceobjdict)
+